How to use ViewModels in Magento 2?

Jun 6th, 2019 6 min to read

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.

FAQs

When to use ViewModel in Magento 2?


You can use ViewModel in Magento 2 to modify, format, or abstract data before using it in a template. ViewModels are good to use when block classes become too complex. With ViewModels, you can keep the templates clean and minimal and also use the block classes to create similar templates.

What is MVVM in Magento 2?


MVVM in Magento 2 stands for Model View ViewModel. It is an architectural system that separates the different development components into three sections: model, view, and ViewModel. The new component, ViewModel, creates true separation between the model and view components, while maintaining a channel between the two. This helps developers write and debug code and simplify web application testing.

Why MVVM is better than MVC?


MVVM is better than MVC because MVVM allows true separation of the model and view layers. This makes it easier to test them as separate units without conflict between different parts of the code which is difficult in MVC. The separation also improves flexibility, allowing developers to utilize a single data set to create multiple ViewModels.

How to override model class in Magento 2?


To override a model class in Magento 2, follow the below-mentioned steps –
1. Create a di.xml file in your module’s etc directory.
2. Define a preference for the original model class using the preference element. 
3. Set the for attribute to the original class name and the type attribute to the new class name.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
 <preference for="Magento\Customer\Model\Customer" type="Vendor\Module\Model\Rewrite\Customer" />
</config>


4. Create a new class in your module’s Model\Rewrite directory. The class should extend the original class and should have the same name as the new class name defined in the di.xml file.

<?php
namespace Vendor\Module\Model\Rewrite;
class Customer extends \Magento\Customer\Model\Customer
{
 // Your custom methods here
}


5. Refresh the cache and run the setup:upgrade command.

Speak your Mind

Post a Comment

Got a question? Have a feedback? Please feel free to leave your ideas, opinions, and questions in the comments section of our post! ❤️

* This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Grow your online business like 3,820 subscribers

    * This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
    envelope

    Thank You!

    We are reviewing your submission, and will be in touch shortly.