Looking in greater detail at Knockout in Magento 2

Now that we have a working component setup we can start taking a look at how powerful KO JS is …

Now that we have a working component setup we can start taking a look at how powerful KO JS is within the context of Magento 2.

Knockout observables

The most useful feature in Knockout JS is the observable along with the observable arrays. It enables you to have dynamic data-binding with variables that are immediately updated in the template when the value within the component changes. An observable array acts in the same way, and like the normal observable you can subscribe to the change events and generate logic within your component when the values change.
So let’s go about updating our component and template to test out an observable.
In our component file, we need to add a new key attached to the component object and assign its value as an observable with an initial value of 0. This allows us to access the ‘myTimer’ value in the template.

define(['jquery', 'uiComponent', 'ko'], function ($, Component, ko) {
        'use strict';
        return Component.extend({
            myTimer: ko.observable(0),
            initialize: function () {
                this._super();
            }
        });
    }
);

We now need to update our template to display our new myTimer variable.

So all of that is great, but it doesn’t really show the data-binding aspect of the observable. Let’s create a timer loop within our component which updates the value every second.

define(['jquery', 'uiComponent', 'ko'], function ($, Component, ko) {
        'use strict';
        
        var self;
        return Component.extend({
            myTimer: ko.observable(0),
            initialize: function () {
                self = this;
                this._super();
                //call the incrementTime function to run on intialize
                this.incrementTime();
            },
            //increment myTimer every second
            incrementTime: function() {
                var t = 0;
                setInterval(function() {
                    t++;
                    self.myTimer(t);
                }, 1000);
            }
        });
    }
);

Notice here that we set the observable value by passing the new value into the observable as we would pass a new value into a function. If you assign a new value to the myTimer as you normally would, it will replace the observable with the value you just assigned, losing its functionality.

The myTimer value is updated every 1000ms on the template. Pretty nice, although this is a very basic example. It’s extremely useful to be able to update values in your JS component and see the results instantly in the template.

Subscribe to observables

You can also subscribe to observables, meaning that when the value of them is changed, an event is fired and you can hook into this in order to run some kind of logic process within another function or multiple functions. So, in our example, we are going to update the colour of the timer text to a random colour every time the myTimer variable updates.

define(['jquery', 'uiComponent', 'ko'], function ($, Component, ko) {
        'use strict';
        var self;
        return Component.extend({
            myTimer: ko.observable(0),
            randomColour: ko.observable("rgb(0, 0, 0)"),
            initialize: function () {
                self = this;
                this._super();
                //call the incrementTime function to run on intialize
                this.incrementTime();
                this.subscribeToTime();
            },
            //increment myTimer every second
            incrementTime: function() {
                var t = 0;
                setInterval(function() {
                    t++;
                    self.myTimer(t);
                }, 1000);
            },
            subscribeToTime: function() {
                this.myTimer.subscribe(function(newValue) {
                    console.log(newValue);
                    self.updateTimerTextColour();
                });
            },
            randomNumber: function() {
                return Math.floor((Math.random() * 255) + 1);
            },
            updateTimerTextColour: function() {
                //define RGB values
                var red = self.randomNumber(),
                    blue = self.randomNumber(),
                    green = self.randomNumber();
                    
                self.randomColour('rgb(' + red + ', ' + blue + ', ' + green + ')');
            }
        });
    }
);

We have added the subscribeToTime function which is called on initialize and subscribes to our myTimer observable. Every time that value is updated, the subscribe function is called upon and, in our case, it console.logs the value of the new myTimer value as well as generating a random colour for the timer text via the new updateTimerTextColour function.
In order for us to see these changes we need to update our template as follows:

As you can see, we can bind multiple events to an element with KO JS and the data-bind syntax by simply separating them with a comma. In the new template above we’ve simply used the native style event which will change the style of the div by assigning our new randomColour observable (generated with updateTimerTextColour) to the colour attribute.
Once you’ve updated both the JS component file and the template file, clear all your cache and refresh the page to see if it’s worked!

Magento 2 and KO JS provide us a great deal of flexibility in order to create rich components which can really enhance the user experience of the end user.

If you want to know more about MagmaLabs, visit us here!

Keep reading

More >