Magento2 – How to Call Multiple Knockout Templates Within One Component

javascriptknockoutjsmagento2requirejsuicomponent

I'm currently experimenting with Knockout JS templates within Magento 2 and all is going well but I do have one thought.

It seems that you can only call <!-- ko template: getTemplate() --><!-- /ko --> once per component as there is no option to create a second template and I can't see any components where Magento are using multiple templates.

Example code:

My Template – app/design/frontend/Ben/blankClone/Magento_Cms/templates/knockout.phtml

<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>

My JS – It's a rough experiment 😉 – app/design/frontend/Ben/blankClone/Magento_Cms/web/js/knockout-example.js

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

    function getRandomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    var messageCollection = ['Hello', 'Hi', 'Yo!', 'Sup?'];

    return Component.extend({
        defaults: {
            exampleMessage: 'This is the default title for my KO example',
            template: 'Magento_Cms/test'
        },

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

        /**
         * @return {exports.initObservable}
         * This is the same as var example = ko.observable('Example text');
         */
        initObservable: function () {
            this._super()
                .observe({
                    message: this.exampleMessage,
                    messageChanged: false,
                    updateTitle: false
                });

            return this;
        },

        updateTitle: function() {
            var numberOfMessages = messageCollection.length;
            var chosenMessageIndex = getRandomInt(0, (numberOfMessages - 1));
            var chosenMessage = messageCollection[chosenMessageIndex];

            this.message(chosenMessage);
            this.messageChanged(true);
        },

        resetTitle: function() {
            this.message(this.exampleMessage);
            this.messageChanged(false);
        },

        addYourOwnTitle: function() {

        }
    });
});

My HTML templates

app/design/frontend/Ben/blankClone/Magento_Cms/web/template/test.html


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!

app/design/frontend/Ben/blankClone/Magento_Cms/web/template/test-two.html

Hi!

So my question is: Is it possible to call a second template? and if so, how?

My thinking is you are limited to only one template per component to force you to write smaller components.

The only lead I have on this is the following markup, but I can't see how to get this working within Magento.

<div data-bind="template: { name: 'person-template'}"></div>

Best Answer

Yes, you should be able to use as many template bindings as you want. You could do this with a string identifier for the template URN

<!-- ko template: "Package_Namespace/template-name" --><!-- /ko -->

or a property on your view model that contains a template string.

<!-- ko template: someProp --><!-- /ko -->

You can also use the above with a <script type="text/html" named template, as per the Knockout docs

If you're unfamiliar with how Knockout template URNs or text/html named templates work in Magento, I cover it OK in my Magento 2: KnockoutJS Integration article. I've also got a comprehensive series on UI Components and their underlying uiElement objects if you want to go really deep.

Related Topic