KnockOutJS - Multiple ViewModels dalam satu Tampilan


201

Saya berpikir bahwa aplikasi saya menjadi cukup besar sekarang, terlalu besar untuk menangani setiap Tampilan dengan satu Model View.

Jadi saya bertanya-tanya betapa sulitnya membuat banyak ViewModels dan memuat semuanya menjadi satu tampilan. Dengan catatan bahwa saya juga harus bisa meneruskan data X ViewModel ke data Y ViewModel sehingga masing-masing ViewModels harus dapat berkomunikasi satu sama lain atau setidaknya saling memperhatikan satu sama lain.

Misalnya saya memiliki <select>drop down, drop down pilih itu memiliki keadaan yang dipilih yang memungkinkan saya untuk melewati ID dari item yang dipilih di <select>ke panggilan Ajax lain di ViewModel terpisah ....

Poin apa pun dalam berurusan dengan banyak ViewModels dalam satu Tampilan dihargai :)


12
Bagi mereka yang tiba di pertanyaan ini, silakan gulir melewati jawaban yang diterima. Knockout sekarang mendukung banyak konteks yang mengikat . Tidak perlu untuk raksasa masterVM.
Carrie Kendall

Jawaban:


150

Jika mereka semua harus berada di halaman yang sama, salah satu cara mudah untuk melakukan ini adalah memiliki model tampilan master yang berisi array (atau daftar properti) dari model tampilan lainnya.

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

Maka Anda masterVMdapat memiliki properti lain jika diperlukan, untuk halaman itu sendiri. Komunikasi antara model tampilan tidak akan sulit dalam situasi ini karena Anda dapat menyampaikan melalui masterVM, atau Anda dapat menggunakan $parent/ $rootdalam binding, atau beberapa opsi khusus lainnya.


2
Jadi saya bisa melakukan sesuatu seperti: data-bind = "text: masterVM.vmA", saya kira saya masih bisa menggunakan ko.applyBindings dengan elemen DOM terlampir. Anggap itu juga berarti saya bisa melakukan: data-bind = "$ parent.masterVm"?
CLiown

12
@ CLiown Anda dapat menggunakan with:bindging, jadi Anda tidak akan mengulangi lagi
AlfeG

4
@ Clown Ya, Anda bisa melakukannya jika Anda terikat pada masterVM. Anda juga dapat menggunakan ikatan "dengan" untuk membantu menghindari sintaksis titik ketika Anda masuk ke model tampilan sub.
John Papa

1
Saya pikir pendekatan ini sangat membatasi ... Sekarang dalam kasus saya, saya menggunakan ASP.Net MVC4, ini tidak membantu karena akan ada pandangan parsial memiliki ViewModels sendiri, dan bagian parsial / Konten, tidak boleh saling mengganggu satu sama lain , dan karena render kondisional Akan sangat sulit untuk menggunakan pendekatan ini.
bhuvin

1
@ Bahuvin menggunakan <! - ko stopBinding: true -> akan membantu Anda dengan beberapa model tampilan dan bagian tampilan sebagian. Lihat knockmeout.net/2012/05/quick-tip-skip-binding.html untuk informasi lebih lanjut.
Micaël Félix

285

Knockout sekarang mendukung pengikatan banyak model. Ituko.applyBindings() Metode mengambil parameter opsional - elemen dan keturunannya yang mengikat akan diaktifkan.

Sebagai contoh:

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

Ini membatasi aktivasi ke elemen dengan ID someElementIddan turunannya.

Lihat dokumentasi untuk lebih jelasnya.


72
Jika Anda ingin menggunakan pemilih jQuery, Anda ingin menambahkan [0]untuk menentukan elemen DOM yang sebenarnya (bukan objek jQuery) seperti:ko.applyBindings(myViewModel, $('#someElementId')[0])
MrBoJangles

3
Ini harus menjadi jawaban yang diterima. Anda masih bisa menggunakan objek master seperti yang dimiliki jawaban yang saat ini diterima, dan kemudian ikat masing-masing model viewm ke elemen yang sesuai di halaman. Ini akan menghemat kinerja, dan membatasi ruang lingkup yang diperlukan untuk pengikatan data.
Kevin Heidt

Apakah mungkin untuk mengkomunikasikan viewModels satu sama lain dengan pendekatan ini? yaitu saya punya TaskVM dan NoteVM. Tugas dapat memiliki Catatan. Oleh karena itu TaskVM saya harus memiliki observableArray yaitu catatan yang tipenya adalah TaskVM. Bisakah Anda membagikan contoh untuk kasus seperti itu?
Ahmet

Mungkin terbaik untuk bertanya tentang komunikasi antara VMs dalam pertanyaan baru.
Richard Nalezynski

21

Ini adalah jawaban saya setelah menyelesaikan proyek yang sangat besar dengan banyak ViewModels dalam tampilan tunggal.

Lihat 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>

Untuk tampilan ini saya membuat 2 model tampilan untuk id = container1 dan id = container2 dalam dua file javascript terpisah.

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

}

Kemudian setelah 2 viewmodels ini mendaftar sebagai viewmodels terpisah di 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"));
    }
});

Seperti ini, Anda dapat menambahkan sejumlah viewmodels untuk divs terpisah. Tetapi pastikan jangan membuat model tampilan terpisah untuk div di dalam div terdaftar.


Apakah mungkin untuk melakukannya dengan model viewmodel di dalam elemen lain daripada menjadi elemen yang terpisah dari DOM?
UserEsp

4

Periksa plugin MultiModels untuk Knockout JS - https://github.com/sergun/Knockout-MultiModels


6
Keuntungan apa yang dimilikinya jika dibandingkan dengan ko.applyBindings (viewModel, document.getElementById ("divName"))? Bukankah itu hanya gula sintaksis?
Paolo del Mundo

1
@ Paolo del Mundo Ia juga menambahkan ketergantungan pada plugin LiveQuery.
Lars Gyrup Brink Nielsen

@PaolodelMundo tujuan dari plugin ini adalah untuk dapat menggunakan set viewmodels dengan cara decalrative
Sergey Zwezdin

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.