javascripthtmlknockout.jsknockout-componentsknockout-templating

WHY does it initialize this Knockout.js component in random order?


I am beyond confused...

I am creating a list using Knockout.js components, templates, and custom elements. For some reason, the steps I create in my Viewmodel are being initialized in random order within the custom element definition! And it is completely randomized so that it is different each time!

To help better illustrate this, it is best to look at the JSFiddle. I put alert("break") after each step initialization. Load it once, and then click "run" again to see the demo properly. Look in the output window and you can see that other than step 1 being written first, the steps always appear randomly (though they maintain their order in the end).

https://jsfiddle.net/uu4hzc41/8/

I need to have these in the correct order because I will add certain attributes from my model into an array. When they are random I can't access the array elements properly.

HTML:

<ul>
    <sidebar-step params="vm: sidebarStepModel0"></sidebar-step>
    <sidebar-step params="vm: sidebarStepModel1"></sidebar-step>
    <sidebar-step params="vm: sidebarStepModel2"></sidebar-step>
    <sidebar-step params="vm: sidebarStepModel3"></sidebar-step>
    <sidebar-step params="vm: sidebarStepModel4"></sidebar-step>
</ul>

JS/Knockout:

//custom element <sidebar-step>
ko.components.register("sidebar-step", {
    viewModel: function (params) {
        this.vm = params.vm;
        alert("break");
    },

    template: "<li data-bind='text: vm.message'>vm.onChangeElement</li>"
});

// model
var SidebarStepModel = function () {
    this.message = ko.observable("step description");

};

// viewmodel
var OrderGuideViewModel = function () {

    this.sidebarStepModel0 = new SidebarStepModel();
    this.sidebarStepModel0.message("step 1");


    this.sidebarStepModel1 = new SidebarStepModel();
    this.sidebarStepModel1.message("step 2");


    this.sidebarStepModel2 = new SidebarStepModel();
    this.sidebarStepModel2.message("step 3");


    this.sidebarStepModel3 = new SidebarStepModel();
    this.sidebarStepModel3.message("step 4");


    this.sidebarStepModel4 = new SidebarStepModel();
    this.sidebarStepModel4.message("step 5");


};

ko.applyBindings(new OrderGuideViewModel());

Solution

  • By default knockout components load asynchronously. In version 3.3 an option was added to allow the component to load synchronously.

    Add synchronous:true when registering to get the behavior you want.

    Example:

    ko.components.register("sidebar-step", {
        viewModel: function (params) {
            this.vm = params.vm;
            alert("break");
        },
    
        template: "<li data-bind='text: vm.message'>vm.onChangeElement</li>",
        synchronous: true
    });