Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockout.js multiple external templates & multiple VM switching fails

I'm using the following:

  • knockout-2.1.0.js
  • koExternalTemplateEngine_all.js

What I'm trying to achieve is the following:

  • Template container loads external HTML and loads a specific VM for that HTML (works).
  • Template container loads/switches to another external HTML, alongside with the other specific VM for that HTML (works).
  • Template container switches back to the first template/VM, alongside with their VM (doesn't work!).

I'm guessing the reason it doesn't work, is because the Template is loaded before the VM (it does give me binding errors).

The structure of my site is as like this (excl. the libraries stated above):

  • index.html (Holds the template container)
  • js/script.js (Holds the main ViewModel)
  • js/firstvm.js (Holds the first ViewModel)
  • js/secondvm.js (Holds the second ViewModel)
  • tmpl/firstvm.html (Template for the first VM)
  • tmpl/secondvm.html (Template for the second VM)

Or simply download the source and view the problem.

Most important parts:

  • index.html

    <button data-bind="click: loadFirstPage">Load first page + ViewModel</button>
    <button data-bind="click: loadSecondPage">Load second page + ViewModel</button>
    < hr />
    <div data-bind="template: { name: function() { return currentTemplate(); }, data: currentData }"></div>
    
  • script.js

    function IndexViewModel() {
    
        var vm = this;
    
        this.currentTemplate = ko.observable();
        this.currentData = ko.observable();
    
        this.loadFirstPage = function() {
            vm.currentTemplate("firstvm");
            vm.currentData(new FirstViewModel());
        };
    
        this.loadSecondPage = function() {
            vm.currentTemplate("secondvm");
            vm.currentData(new SecondViewModel());
        };
    
        this.loadFirstPage();
    };
    ko.applyBindings(new IndexViewModel());
    
  • firstvm.html

    <p data-bind="text: displayValue"></p>
    
  • secondvm.html

    <p data-bind="text: displayValue2"></p>
    
  • firstvm.js

    function FirstViewModel() {
        this.displayValue = ko.observable("Text from firstvm.js");
    };
    
  • secondvm.js

    function SecondViewModel() {
        this.displayValue2 = ko.observable("Text from secondvm.js");
    };
    

I hope somebody can help me out with this one. Thanks in advance!

Ps. Forgot to mention: When the "First page" button is pressed twice, it does seem to work (probably since the correct VM is loaded).

like image 277
MarcoK Avatar asked Jul 31 '12 13:07

MarcoK


1 Answers

So it looks like the issue is that the name and data need to change at the same time, so that the template isn't binding to a viewmodel that isn't there yet. There are a few ways you could solve this. One would be loading the templates and keeping them, but you could continue reloading them like this:

Template Binding:

<div data-bind="template: {name: currentTemplate().name(), 
                data: currentTemplate().data() }"></div>

ViewModel:

function TemplateViewModel(name, data) {
        this.name = ko.observable(name);
        this.data = ko.observable(data);
    };

    function IndexViewModel() {

        var vm = this;

        this.currentTemplate = ko.observable();

        this.loadFirstPage = function() {           
            vm.currentTemplate(new TemplateViewModel("firstvm", new FirstViewModel()));
        };

        this.loadSecondPage = function() {
            vm.currentTemplate(new TemplateViewModel("secondvm", new SecondViewModel()));
        };

        this.loadFirstPage();
    };
    ko.applyBindings(new IndexViewModel());

I tested this, it works. You may want to tweak it a bit more, but you get the idea.

like image 103
Kyeotic Avatar answered Nov 15 '22 06:11

Kyeotic