Hey to Amasty blog readers!
Today we are going to talk about using Knockout in Magento 2 frontend solutions.
Introduction of this library brought significant positive changes to Magento 2 development and made it possible to create a much wider range of responsive frontend components, such as datepicker, popups, and other custom design elements.
Despite the benefits, implementing Magento 2 solutions with Knockout is quite complicated for many developers. So, today we look at how KO works and how you can use it in your Magento 2 projects.
How Knockout works in Magento 2
How Knockout works in Magento 2 UI components
To be more specific, a UI component implements a part of the MVVM design pattern. A Model here is a piece of Knockout code that contains the business logic of the component, and a View is a relevant HTML document that describes how the component is rendered.
The frontend Knockout files are conventionally located as follows:
To make it more vivid, consider the checkout component as an example.
First, we access the Model via module-checkout\view\frontend\web\js\view\review\actions\default.js, and see the following code representation:
The path to the component template is shown in the defaults section of the component and takes the form of an object with the key named template. The Model contains information about all the functions that will be used in the View part of the component. Also, the Model is used to declare all observable variables, for example, placeOrder.
Second, the View is located in the module-checkout\view\frontend\web\template\review\actions\default.html and looks as below:
The component template contains special Knockout directives used for binding the View with the Model.
For more information about Knockout directives and binding, check the Knockout official documentation.
The great thing about Knockout is
While observables are perfect for detecting and responding to changes of one object, working with changes in a collection of things requires an observableArray. The observableArray tracks which objects are in the array, yet not their state. Put simply, the observableArray notifies subscribers when objects are added, removed, filtered, rearranged, etc.
Overall, observables help developers create logic for diverse cases that require instant reaction to changes of certain objects.
Knockout observables in action
Now, let’s consider an example of using observables. We access the Model via the path module-customer\view\frontend\web\js\view\authentication-popup.js and declare the isLoading variable as observable using a relevant keyword – observable.
Now, let’s move on to the View part which also contains the isLoading variable. The path is: module-customer\view\frontend\web\template\authentication-popup.html.
Finally, take a look at an example of an event subscription:
We access module-checkout/view/frontend/web/js/view/cart/totals.js and see:
In the code, you can see that subscription regards the Totals observable. Now when the Totals changes, a related function will trigger the Resize event.
Knockout for data exchange between UI components
Here’s an example of the data model of the Checkout Module that we access via module-checkout/view/frontend/web/js/model/shipping-service.js:
Pay attention to the setShippingRates method that affects an observable variable named shippingRates. This method is used in the following model as well module-checkout/view/frontend/web/js/model/shipping-rate-processor/customer-address.js:
In this model, we apply dependencies to transfer the shippingService model into the customerAddress model and use the method setShippingService of the shippingService model. Also, the observable isLoading variable is updated. This way, we connect the customerAddress model to the shippingService model and enable data exchange between the two.
Knockout and using a UI component in a page layout
Now, let’s look at an example of implementing a UI component in a layout file. After we access the XML file located in Amasty/Extrafee/view/frontend/layout/checkout_cart_index.xml, we get:
In the component section, we set the route to the Model file responsible for the Knockout code of the component. The View template can be specified either in the Knockout code or in the config section of the layout of the page (that is checkout_cart_index in our case).
This is how it looks like in the example above:
Below you can see fragments of the code of the component Block in the Amasty Extrafee Module (Amasty_Extrafee/js/view/checkout/cart/block).
In the Model Amasty/Extrafee/view/frontend/web/js/view/checkout/cart/block.js, we see:
And the View model located in Amasty/Extrafee/view/frontend/web/template/checkout/cart/block.html looks like this:
Knockout and server to UI component data transfer
Every Magento 2 page includes a LayoutProcessor responsible for a component generation. To convey dynamic variables to the frontend, you should create the LayoutProcessor class in the Module folder named Block.
The LayoutProcessor class is inherited from \Magento\Checkout\Block\Checkout\LayoutProcessorInterface.
Then, in the LayoutProcessor class, we realize the Process method which accepts the input of a jsLayout variable. The jsLayout is rather an array variable than just a variable as it contains information about all components that belong to this page.
Using this array variable, we can refer to our component and change/add any variables that we need to use on the frontend of the component.
Check this example of realizing the Process method in Amasty/Extrafee/Block/Cart/LayoutProcessor.php:
Today, we looked at how Knockout works in Magento 2. In particular, we learned to use Knockout observables in UI components, add UI components to a page layout, enable data exchange between UI components, and allow data transfer from a server to the frontend of a component.
Hope this article helped you to understand Knockout better and looking forward to your comments and ideas in the feed below.