5

私は以下を使用しています:

私が達成しようとしているのは次のとおりです。

  • テンプレート コンテナは外部 HTML をロードし、その HTML 用の特定の VM をロードします (機能します)。
  • テンプレート コンテナは、その HTML 用の他の特定の VM とともに、別の外部 HTML にロード/切り替えます (機能します)。
  • テンプレート コンテナーは、VM と共に最初のテンプレート/VM に戻ります (動作しません!)。

うまくいかない理由は、テンプレートが VM の前に読み込まれるためだと思います (バインディング エラーが発生します)。

私のサイトの構造は次のとおりです(上記のライブラリを除く):

  • index.html(テンプレート コンテナを保持)
  • js/script.js(メインの ViewModel を保持します)
  • js/firstvm.js(最初の ViewModel を保持します)
  • js/secondvm.js(2 番目の ViewModel を保持します)
  • tmpl/firstvm.html(最初の VM のテンプレート)
  • tmpl/secondvm.html(2 番目の 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>
    
  • 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");
    };
    

誰かがこれで私を助けてくれることを願っています。前もって感謝します!

Ps。言及するのを忘れました:「最初のページ」ボタンを2回押すと、機能しているように見えます(おそらく正しいVMがロードされているため)。

4

2 に答える 2

8

したがって、名前とデータを同時に変更する必要があるため、テンプレートがまだ存在しないビューモデルにバインドされないようにすることが問題のようです。これを解決する方法はいくつかあります。1 つはテンプレートをロードして保持することですが、次のように再ロードを続けることができます。

テンプレートバインディング:

<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以降 、オブザーバブルも受け入れます。name

于 2013-02-13T11:50:03.700 に答える