Pass data to a template using a ViewModel

We’ve created a view model, but now to get access to that ViewModel. We’ll do that by injecting it as an argument to the block, and we will do this with layout XML.

Within view/frontend/layout let’s open up the blog post list XML file. And rather than having this block tag be a self-closing tag, let’s open it up.

Within it, we will create an arguments node that has an argument child node. The name of this argument can be whatever we wish. We will name it “post”, but append an “_vm” to the end, to signify this is a ViewModel and to avoid ambiguity with posts in our code. This will have an xsi:type of object, and the value of this argument will be the fully qualified class name to our ViewModel.

view/frontend/layout/blog_post_list.xml

<?xml version="1.0"?>
<page layout="1column" xmlns:xsi="<http://www.w3.org/2001/XMLSchema-instance>" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="main">
            <block name="blog.list" template="Macademy_Blog::post/list.phtml">
                <arguments>
                    <argument name="post_vm" xsi:type="object">Macademy\\Blog\\ViewModel\\Post</argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

Now this post ViewModel is accessible as data of the block. Let’s create a new $postVm variable, and we will assign it the result of $block->getData('post_vm'). This “post_vm” references the name we assigned in the layout XML (toggle back to show).

Just like a $block typehint is defined at the top of this template file, we should also create one for this new $postVm variable to add intellisense lookups to this variable. So, let’s create a new typehint using @var for our new $postVmvariable that references the Macademy\\Blog\\ViewModel\\Post class.

Now we can create a foreach loop that calls our Post ViewModel’s getList function. We will iterate over this, assign the value to $post. Let’s space out these lines for readability. I also like to take the approach of not caring how this HTML is outputted with indents on the frontend, but instead optimize the indentation for backend readability. This makes your code easier to read from a programming standpoint and really doesn’t have any downsides.

Let’s update the hard-coded id with a call to $post->getData(), and we will fetch the id. We’ll do the same for the title by calling $post->getData('title'). We can also just call both of these with getId() or getTitle(), I prefer the longhand getData approach though because it’s more explicit and you can Cmd+Click or Alt+Click into it in IDEs.

Macademy_Blog::post/list.phtml

<?php
/** @var Magento\\Framework\\View\\Element\\Template $block */
/** @var Macademy\\Blog\\ViewModel\\Post $postVm */
$postVm = $block->getData('post_vm');
?>
<div class="blog-post-list">
    <h1><?= __('Blog posts') ?></h1>
    <ul>
        <?php foreach ($postVm->getList() as $post): ?>
            <li>
                <a href="<?= $block->getUrl('blog/post/detail', ['id' => $post->getData('id')]) ?>">
                    <?= $post->getData('title') ?>
                </a>
            </li>
        <?php endforeach ?>
    </ul>
    <p><?= __('Post count: %1', 3) ?></p>
</div>

Now when we refresh the page, we can see that our new post data is being pulled in from the ViewModel.

Complete and Continue  
Extra lesson content locked
Enroll to access all lessons, source code & comments.
Enroll now to Unlock