5

我正在使用以下内容:

我想要达到的目标如下:

  • 模板容器加载外部 HTML 并为该 HTML 加载特定的 VM(有效)。
  • 模板容器加载/切换到另一个外部 HTML,以及该 HTML 的另一个特定 VM(工作)。
  • 模板容器与它们的 VM 一起切换回第一个模板/VM(不起作用!)。

我猜它不起作用的原因是因为模板是在 VM 之前加载的(它确实给了我绑定错误)。

我的网站的结构是这样的(不包括上述库):

  • index.html(持有模板容器)
  • js/script.js(持有主 ViewModel)
  • js/firstvm.js(持有第一个 ViewModel)
  • js/secondvm.js(持有第二个 ViewModel)
  • tmpl/firstvm.html(第一个虚拟机的模板)
  • tmpl/secondvm.html(第二个虚拟机的模板)

或者只是下载源代码并查看问题。

最重要的部分:

  • 索引.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>
    
  • 脚本.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>
    
  • 第一个vm.js

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

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

我希望有人可以帮助我解决这个问题。提前致谢!

附言。忘了提一下:当两次按下“首页”按钮时,它似乎确实有效(可能是因为加载了正确的虚拟机)。

4

2 回答 2

8

所以看起来问题是名称和数据需要同时更改,因此模板没有绑定到尚不存在的视图模型。有几种方法可以解决这个问题。一种是加载模板并保留它们,但您可以像这样继续重新加载它们:

模板绑定:

<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());

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

于 2012-07-31T16:59:14.160 回答
1

这已经得到解答,但是我想分享我与标准淘汰模板一起使用的解决方案。我创建了自定义绑定,并将模板渲染调用包装到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);

    }
}

注意:由于模板绑定的淘汰赛 2.3 也接受 observablename

于 2013-02-13T11:50:03.700 回答