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.
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
object, and the value of this argument will be the fully qualified class name to our ViewModel.
<?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>
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
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
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.
<?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.