KnockOutJS-単一のビュー内の複数のViewModel


201

アプリケーションが非常に大きくなり、単一のViewModelで各ビューを処理するには大きすぎると思っています。

したがって、複数のViewModelを作成し、それらすべてを単一のViewにロードするのがどれほど難しいか疑問に思っています。XのViewModelデータをYのViewModelデータに渡すこともできるようにする必要があるので、個々のViewModelが相互に通信できるようにするか、少なくとも相互に認識できる必要があることに注意してください。

たとえば、私は<select>ドロップダウンを持っています、その選択ドロップダウンには選択された状態があり<select>、別のViewModel ....で別のAjax呼び出しにで選択されたアイテムのIDを渡すことができます。

単一のビューで多数のViewModelを処理する上での重要な点は高く評価されています:)


12
この質問が表示された場合は、受け入れられた回答をスクロールしてください。 Knockoutは複数のバインディングコンテキストをサポートするようになりました。巨人は必要ありませんmasterVM
Carrie Kendall

回答:


150

すべてを同じページに配置する必要がある場合、これを行う簡単な方法の1つは、他のビューモデルの配列(またはプロパティリスト)を含むマスタービューモデルを用意することです。

masterVM = {
    vmA : new VmA(),
    vmB : new VmB(),
    vmC : new VmC(),
}

次に、masterVM必要に応じて、ページ自体に他のプロパティを設定できます。この状況では、を介してリレーしmasterVMたり、バインディングで$parent/ $rootを使用したり、その他のカスタムオプションを使用したりできるため、ビューモデル間の通信は難しくありません。


2
したがって、data-bind = "text:masterVM.vmA"のようなことを実行できますか?DOM要素をアタッチした状態でko.applyBindingsを引き続き使用できると思います。それはまた私ができることを意味すると思います:data-bind = "$ parent.masterVm"?
CLiown

12
@CLiownバインドを使用できるwith:ので、自分自身を繰り返すことはありません
AlfeG

4
@CLiownはい、masterVMにバインドしている場合はそれが可能です。また、「with」バインディングを使用して、サブビューモデルに飛び込むときにドット構文を回避することもできます。
ジョン・パパ

1
私はこのアプローチは非常に制限的なものだと思います...私の場合、私はASP.Net MVC4を使用していますが、独自のViewModelsを持つパーシャルビューとパーシャル/コンテンツセクションが互いに干渉しないため、これは役に立ちません、そして条件付きレンダリングのため、このアプローチを使用することは本当に難しいでしょう。
bhuvin 2013

1
@bhuvinで<!-ko stopBinding:true->を使用すると、複数のビューモデルと部分的なビューのセクションで役立ちます。詳細については、knockmeout.net / 2012/05 / quick-tip-skip-binding.htmlをご覧ください。
ミカエルフェリックス2014

285

Knockoutは複数のモデルバインディングをサポートするようになりました。のko.applyBindings()メソッドは、オプションのパラメーター(バインディングがアクティブ化される要素とその子孫)を取ります。

例えば:

ko.applyBindings(myViewModel, document.getElementById('someElementId'))

これにより、ID someElementIdを持つ要素とその子孫へのアクティブ化が制限されます。

詳細については、ドキュメントを参照してください。


72
あなたはjQueryのセレクタを使用したい場合は、追加したいと思う[0]ようなので、(代わりにjQueryオブジェクトの)実際のDOM要素を指定するために:ko.applyBindings(myViewModel, $('#someElementId')[0])
MrBoJangles

3
これは受け入れられる答えになるはずです。現在受け入れられている回答のようなマスターオブジェクトを使用して、個々のビューモデルをページ上の適切な要素にバインドすることもできます。これにより、パフォーマンスが節約され、データバインドに必要なスコープが制限されます。
Kevin Heidt 2014

このアプローチでviewModelを互いに通信することは可能ですか?つまり、TaskVMとNoteVMがあります。タスクはメモを持つことができます。したがって、私のTaskVMには、observableArray、つまりタイプがTaskVMであるノートが必要です。そのようなケースの例を共有できますか?
2016年

新しい質問でVM間の通信について質問するのがおそらく最善です。
Richard Nalezynski

21

これは、単一のビューに多数のViewModelを含む非常に大きなプロジェクトを完了した後の私の答えです。

HTMLビュー

    <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <div id="container1">
        <ul>
            <li >Container1 item</li>
            <!-- ko foreach: myItems -->
            <li>Item <span data-bind="text: $data"></span></li>
            <!-- /ko -->
        </ul>
    </div>

    <div id="container2">
        <ul>
            <li >Container2 item</li>
            <!-- ko foreach: myItems -->
                <li>Item <span data-bind="text: $data"></span></li>
            <!-- /ko -->
        </ul>
    </div>

    <script src="js/jquery-1.11.1.js"></script>
    <script src="js/knockout-3.0.0.js"></script>
    <script src="js/DataFunction.js"></script>
    <script src="js/Container1ViewModel.js"></script>
    <script src="js/Container2ViewModel.js"></script>

</body>
</html>

このビューでは、id = container1とid = container2の2つのビューモデルを2つの別個のJavaScriptファイルで作成しています。

Container1ViewModel.js

function Container1ViewModel()
{
    var self = this;
    self.myItems = ko.observableArray();
    self.myItems.push("ABC");
    self.myItems.push("CDE");

} 

Container2ViewModel.js

function Container2ViewModel() {
    var self = this;
    self.myItems = ko.observableArray();
    self.myItems.push("XYZ");
    self.myItems.push("PQR");

}

次に、これら2つのビューモデルがDataFunction.jsの個別のビューモデルとして登録された後

var container1VM;
var container2VM;

$(document).ready(function() {

    if ($.isEmptyObject(container1VM)) {
        container1VM = new Container1ViewModel();
        ko.applyBindings(container1VM, document.getElementById("container1"));
    }

    if ($.isEmptyObject(container2VM)) {
        container2VM = new Container2ViewModel();
        ko.applyBindings(container2VM, document.getElementById("container2"));
    }
});

このように、個別のdivに任意の数のビューモデルを追加できます。ただし、登録されたdiv内のdivに対して個別のビューモデルを作成しないでください。


DOMの個別の要素になる代わりに、他の内部でビューモデルを実行することは可能ですか?
UserEsp 2018

4

Knockout JSのMultiModelsプラグインを確認してください-https ://github.com/sergun/Knockout-MultiModels


6
これはko.applyBindings(viewModel、document.getElementById( "divName"))に比べてどのような利点がありますか?それは単に構文上の砂糖ではないですか?
Paolo del Mundo 2013年

1
@Paolo del Mundoまた、LiveQueryプラグインへの依存を追加します。
Lars Gyrup Brink Nielsen

@PaolodelMundoプラグインの目的は、declarativeな方法でビューモデルのセットを使用できるようにすることです
Sergey Zwezdin

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.