javascriptknockout.jsknockout-components

Alter the template from the `createViewModel` function within a custom component loader


In knockoutjs I have a custom component loader in which I do some logic. Basically I want to alter the template from the createViewModel function. I know there's the componentInfo.templateNodes but I don't know what to do with it.

The reason I want to alter it in the createViewModel function is because the createViewModel function is called every time a component is shown.

Ahwell, code says way more than words so check it out yourself down here.

ko.components.loaders.unshift({
    getConfig: function (name, callback) {
        var component;  // The component gets loaded somewhere. (Sadly I can't alter the template here because it is only called once.)

        callback({
            viewModel: {
                createViewModel: function (params, componentInfo) {
                    // Load these parameters somewhere
                    var args;
                    var location;

                    // I'd love to add these two items before and after my template.
                    var before = "<div data-bind=\"with: " + location + "\">";
                    var after = "</div>";

                    // Construct a viewModel with the data provided. 
                    return app.core.helpers.construct(component.viewModel, location, args);
                }
            },
            template: component.template
        });
    },

    loadTemplate: function (name, template, callback) {
        // Get the location again.
        var location;

        // I just want to load the template while applying the correct binding scope from the createViewModel.
        var templateString = "<!-- ko stopBinding: true -->\n<!-- ko with: " + location + " -->\n" + template + "\n<!-- /ko -->\n<!-- /ko -->";

        // Just let it load.
        ko.components.defaultLoader.loadTemplate(name, templateString, callback);
    }
});

Solution

  • I managed to create a working solution (although in its infancy). As I still don't know how to add template code to the componentInfo I discovered it is possible to edit the things available in the componentInfo. (See the solution below)

    ko.components.loaders.unshift({
        getConfig: function (name, callback) {
            var component;
    
            callback({
                viewModel: {
                    createViewModel: function (params, componentInfo) {
                        // Load these parameters somewhere
                        var args;
                        var location;
    
                        /*
                         *  The first one is the element we're binding on. The next sibling is the element we probably want to alter.
                         */ 
                        if (componentInfo.element.nextSibling.nodeType == 8 && componentInfo.element.nextSibling.nodeValue.indexOf("[injectNamespace]") > -1) {
                            componentInfo.element.nextSibling.nodeValue =  "ko with: models." + name.replace('/', '.');
                        }
    
                        return app.core.helpers.construct(component.viewModel, location, args);
                    }
                },
                template: component.template
            });
        },
    
        loadTemplate: function (name, template, callback) {
            var templateString = "<!-- ko with: [injectNamespace] -->\n" + template + "\n<!-- /ko -->";
    
            ko.components.defaultLoader.loadTemplate(name, templateString, callback);
        }
    });