Javascript Knockout.js多个外部模板&;多个虚拟机切换失败

Javascript Knockout.js多个外部模板&;多个虚拟机切换失败,javascript,templates,mvvm,knockout.js,Javascript,Templates,Mvvm,Knockout.js,我正在使用以下命令: 淘汰赛-2.1.0.js 我正在努力实现以下目标: 模板容器加载外部HTML并加载该HTML的特定VM(工作) 模板容器加载/切换到另一个外部HTML,以及该HTML的其他特定VM(工作) 模板容器切换回第一个模板/VM以及它们的VM(不工作!) 我猜它不起作用的原因是,模板是在VM之前加载的(它确实会给我绑定错误) 我的网站结构如下(不包括上述图书馆): index.html(保存模板容器) js/script.js(保存主视图模型) js/firstvm.j

我正在使用以下命令:

  • 淘汰赛-2.1.0.js
我正在努力实现以下目标:

  • 模板容器加载外部HTML并加载该HTML的特定VM(工作)
  • 模板容器加载/切换到另一个外部HTML,以及该HTML的其他特定VM(工作)
  • 模板容器切换回第一个模板/VM以及它们的VM(不工作!)
我猜它不起作用的原因是,模板是在VM之前加载的(它确实会给我绑定错误)

我的网站结构如下(不包括上述图书馆):

  • index.html
    (保存模板容器)
  • js/script.js
    (保存主视图模型)
  • js/firstvm.js
    (保存第一个视图模型)
  • js/secondvm.js
    (保存第二个视图模型)
  • tmpl/firstvm.html
    (第一个VM的模板)
  • tmpl/secondvm.html
    (第二个VM的模板)

最重要的部分:

  • 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>
    
  • firstvm.html

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

    function SecondViewModel() {
        this.displayValue2 = ko.observable("Text from secondvm.js");
    };
    
我希望有人能帮我解决这个问题。提前谢谢


注:忘记提及:当两次按下“首页”按钮时,它似乎确实起作用(可能是因为加载了正确的虚拟机)。

因此,问题似乎是名称和数据需要同时更改,这样模板就不会绑定到尚未存在的viewmodel。有几种方法可以解决这个问题。一种方法是加载模板并保留它们,但您可以继续这样重新加载它们:

模板绑定:

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

我测试了这个,它是有效的。您可能想对其进行更多的调整,但您已经明白了。

这已经得到了回答,但是我想与大家分享我的解决方案,该解决方案用于标准的淘汰模板。我创建了自定义绑定,并将模板渲染调用包装到
setTimeout
中,以将渲染放在队列的末尾,效果很好。代码如下:

ko.bindingHandlers.widget = {
    'init': function(element, valueAccessor) {
        return { 'controlsDescendantBindings': true };
    },
    'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var templateName = valueAccessor().widgetTemplate();
        var dataValue = valueAccessor()
        var innerBindingContext = bindingContext['createChildContext'](dataValue);

        // This puts rendering of template to end of queue. 
        // This is to avoid binding errors while new template is assigned to old widget data
        setTimeout(function(){
            ko.renderTemplate(templateName, innerBindingContext, {}, element);
        }, 0);

    }
}

注意:自从模板绑定的
名称
以来

您是否尝试将模板:{name:}绑定更改为直接绑定到计算的或可观察的而不是函数?在这种情况下,ko应该自动评估更改。@Nick Yup。不幸的是,这不起作用。
data bind=“template:{name:currentmplate,data:currentData}”
对我有效。是的,这就是诀窍!问题确实是模板和数据需要同时更改,但我没有想到这个解决方案。这么简单,但有效-谢谢!绝妙的解决方案!请注意,您不需要额外的TemplateViewModel()函数。只需使用:
vm.currentTemplate({name:'firstvm',data:new FirstViewModel()}),就可以使它变得简单一点
function SecondViewModel() {
    this.displayValue2 = ko.observable("Text from secondvm.js");
};
<div data-bind="template: {name: currentTemplate().name(), 
                data: currentTemplate().data() }"></div>
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());
ko.bindingHandlers.widget = {
    'init': function(element, valueAccessor) {
        return { 'controlsDescendantBindings': true };
    },
    'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var templateName = valueAccessor().widgetTemplate();
        var dataValue = valueAccessor()
        var innerBindingContext = bindingContext['createChildContext'](dataValue);

        // This puts rendering of template to end of queue. 
        // This is to avoid binding errors while new template is assigned to old widget data
        setTimeout(function(){
            ko.renderTemplate(templateName, innerBindingContext, {}, element);
        }, 0);

    }
}