How to use Knockout JS within Magento 2

Simple method where you DO NOT need to use html templates

Thanks to Vinai Kopp I've finally got an answer to this, it is much simpler than my previous hacky workaround (I was cleaning nodes). All you need to do is define 'ko' as a dependency and add your code inside a return function.

Below is a simple example that renders out some text passed in via JSON.

app/code/VENODR/MODULE/view/frontend/templates/knockout-example.phtml

Here we tell Magento the scope of our components (this must match data-bind: "scope: 'example-scope'" and pass any additional data. This could be the base URL, a simple message, pretty much anything you want. I've passed a string (PHP echo) as an example

<script type="text/x-magento-init">
{
    "*": {
        "Magento_Ui/js/core/app": {
            "components": {
                "example-scope": {
                    "component": "VENDOR_MODULE/js/knockout-example",
                    "exampleMessage": "<?= __('Hello Magento Stack Exchange!') ?>"
                }
            }
        }
    }
}
</script>

<div data-bind="scope: 'example-scope'">
    <h2 data-bind="text: message"></h2>
</div>

And here we write our Javascript.

app/code/VENDOR/MODULE/view/frontend/web/js/knockout-example.js

define(['ko'], function(ko) {
    return function(config) {
        this.message = ko.observable(config.exampleMessage);
    }
});

 Result

enter image description here

---------------------

Method where you DO need to use HTML templates

If you want to use the HTML templating system within Magento2/Knockout (which I presume you will need for any significant pieces of work) there are a few changes you'll need to make compared to my simplified answer (below).

If you don't require the template functionality then scroll down to my old simplified answer.

The files I'm using for this example are:

  • app/design/frontend/VENDOR/THEME/Magento_Cms/templates/knockout.phtml
  • app/design/frontend/VENDOR/THEME/Magento_Cms/web/js/knockout-example.js
  • app/design/frontend/VENDOR/THEME/Magento_Cms/web/template/test.html

The PHTML template file

The only change to our PHTML template is the call to the getTemplate() function:

<script type="text/x-magento-init">
{
    "*": {
        "Magento_Ui/js/core/app": {
            "components": {
                "example-scope": {
                    "component": "Magento_Cms/js/knockout-example",
                    "exampleMessage": "<?= __('Hello Magento Stack Exchange!') ?>"
                }
            }
        }
    }
}
</script>

<div data-bind="scope: 'example-scope'">
    <h2 data-bind="text: message"></h2>
    <!-- ko template: getTemplate() --><!-- /ko -->
</div>

The JS (component) file

There are a few changes you'll need to make to the JS file, I'll detail these below.

define(['ko', 'uiComponent'], function(ko, Component) {
    'use strict';

    return Component.extend({
        defaults: {
            exampleMessage: 'Hello?',
            template: 'Magento_Cms/test'
        },

        initialize: function() {
            this._super();
            console.log(this.exampleMessage);
            this.message = ko.observable(this.exampleMessage);
        }
    });
});

1 - Your return function now needs to extend the uiComponent module:

return Component.extend({
    ...
});

2 - You need to add an initialize function and call this._super(). this._super() will call the parent component's function with the same name. So in this instance I think it will call initialize of uiComponent.

initialize: function() {
    this._super();
    ...
}.

3 - Optional - You can also set some defaults for your component here, I think this is a good practice to follow as it makes your component easy to work with. When you reuse it you can either keep the defaults or if you want to customise it you can call it with new arguments without altering the component.

For example, if you look at defaults in the JS it sets exampleMessage to 'Hello?' yet the page is rendering the text as Hello Magento Stack Exchange!. This is because I've overwritten exampleMessage in the PHTML file when I've called the component.

The HTML template

I'm still to dig around and see what the HTML templates are capable of, I presume the features mentioned on the Knockout JS documentation can be used in here making them pretty flexible.

I have just added some lorem ipsum text for now, I will likely provide another question/answer once I've figured out what the HTML templates can do.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores assumenda beatae blanditiis culpa cupiditate doloremque, expedita ipsum iure magni minima modi molestiae nulla optio porro ratione reiciendis repellat soluta voluptatum!

The result, and overwriting the defaults

As mentioned before you can see that I have overwritten exampleMessage within the template, you can see it working as the text reads Hello Magento Stack Exchange.

enter image description here

If I remove the override in the template file exampleMessage will return to it's default of Hello?. I did need to delete var/view_preprocessed and pub/static/frontend after changing this though. I presume Magento had cached the value.

enter image description here


https://github.com/seeni9589/Magento2/tree/master/Smart/Feedback

Custom Feedback form with the knockout js. Hope it helps.