How to use ViewModels in Magento 2?

In this post, I will be guiding you on how to use ViewModels in Magento 2.

Magento 2.2 has done many improvements and one of these is the concept of ViewModels, offloading features from Block classes into separate ViewModel classes.

Why use ViewModels instead of Blocks?

As most of the Block classes that exist in Magento 2 are created by extending upon the \Magento\Framework\View\Element\Template class. Usually, when you create a Block class, you can reuse a lot of functionality from the parent class. But as your class grows in functionality, you might need to insert other dependencies into your Block class. And the way to do that is to override the PHP constructor and add your own dependencies to it. To make sure your parent constructor still works, you need to duplicate all of the parent dependencies and pass them on to the parent like follows:

<?php
namespace Aureatelabs\ModuleName\Block;
class CustomBlock extends \Magento\Framework\View\Element\Template
{
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        array $data = []
    ) {
        parent::__construct($context, $data);
    }
}

You need to add more code to a PHP constructor, only to satisfy the parent class. If there was no parent class at all, you would not need to add parent dependency like $context or $data to your class in the first place. Inheritance is working against us, making a simple class more complex. We are not maintaining our class only, we are also maintaining the stuff that lives in our parent class.

ViewModels are there to simplify things again. Instead of inserting your dependency in the Block class, you add it to the ViewModel class. And while you would normally reference $block->getSomething() to get the result of that dependency from your class into your template file, you have to use $viewModel->getSomething().

Follow the below steps to use ViewModels in Magento 2.

Here we will be using Aureatelabs as the Vendor name and ModuleName as the name of the module. You can change this according to your Vendor and Module name.

Step 1: Define View Model argument in Block

You can just add an additional XML argument to the Block class, either when creating the block using <block> or when referring to the block using <referenceBlock>. This might look like the following:

<block name="example-view-model" class="Magento\Framework\View\Element\Template" template="Aureatelabs_ModuleName::test.phtml">
    <arguments>
        <argument name="view_model"
                  xsi:type="object">Aureatelabs\ModuleName\ViewModel\Custom</argument>
    </arguments>
</block>

Here we have defined our ViewModel Class Aureatelabs\ModuleName\ViewModel\Custom in the view_model argument of Block.

Since Magento 2.2.1, we don’t even have to specify the class argument on the <block/> node because if class argument not found it will take the default class "Magento\Framework\View\Element\Template".

Step 2: Define View Model Class

Now we will create a Custom.php in Aureatelabs\ModuleName\ViewModel as we defined in Block.

<?php
namespace Aureatelabs\ModuleName\ViewModel;

use Magento\Framework\View\Element\Block\ArgumentInterface;

class Custom implements ArgumentInterface
{
    public function __construct() {

    }

    public function getSomething()
    {
        return "Hello World";
    }
}

When you use ViewModel class, it must implement Magento\Framework\View\Element\Block\ArgumentInterface.

A constructor does not need to call parent::__construct(), and you can modify the constructor to inject new dependencies as you are used to in other classes.

Step 3: Use ViewModel class in your existing PHTML file

You can insert the new ViewModel class in your existing PHTML template as follows.

<?php
/**@var Aureatelabs\ModuleName\ViewModel\Custom $viewModel*/
$viewModel = $block->getData('view_model');
?>

<?= $viewModel->getSomeThing()?>

ViewModels working in Magento 2.0 or 2.1?

We can use ViewModels in Magento 2.2 and the greater version. But it will not work with Magento 2.0 and 2.1 versions.  Because XSI type Object is not available in Magento 2.0 or 2.1 version.

In short, using ViewModels in Magento 2.0 and  2.1 will give you an error.

  • Share :