KnockOutJS - ViewModels multipli in una singola vista


201

Sto pensando che la mia applicazione sta diventando abbastanza grande ora, troppo grande per gestire ogni vista con un singolo ViewModel.

Quindi mi chiedo quanto sarebbe difficile creare più ViewModel e caricarli tutti in un'unica vista. Con una nota che devo anche essere in grado di passare i dati X ViewModel in Y ViewModel , in modo che i singoli ViewModel debbano essere in grado di comunicare tra loro o almeno conoscersi.

Ad esempio, ho un <select>menu a discesa, quel menu a discesa selezionato ha uno stato selezionato che mi consente di passare l'ID dell'elemento selezionato nel <select>a un'altra chiamata Ajax in un ViewModel separato ....

Apprezzati tutti i punti relativi alla gestione di numerosi ViewModel in un'unica vista :)


12
Per chi arriva a questa domanda, scorri oltre la risposta accettata. Knockout ora supporta più contesti di associazione . Non è necessario un gigante masterVM.
Carrie Kendall,

Risposte:


150

Se devono essere tutti sulla stessa pagina, un modo semplice per farlo è quello di avere un modello di vista principale contenente un array (o un elenco di proprietà) degli altri modelli di vista.

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

Quindi masterVMpuoi avere altre proprietà se necessario, per la pagina stessa. La comunicazione tra i modelli di vista non sarebbe difficile in questa situazione in quanto è possibile inoltrare tramite masterVM, oppure è possibile utilizzare i collegamenti $parent/ $rootin, o alcune altre opzioni personalizzate.


2
Quindi sarei in grado di fare qualcosa del tipo: data-bind = "text: masterVM.vmA", suppongo che potrei ancora usare ko.applyBindings con l'elemento DOM collegato. Supponiamo che significhi anche che potrei fare: data-bind = "$ parent.masterVm"?
Chiuso

12
@CLiown Puoi usare il with:bindging, quindi non ti ripeterai
AlfeG,

4
@CLiown Sì, potresti farlo se ti legassi a masterVM. È inoltre possibile utilizzare l'associazione "con" per evitare la sintassi del punto quando ci si immerge nei modelli della vista secondaria.
John Papa,

1
Penso che questo approccio sia molto restrittivo ... Ora nel mio caso sto usando ASP.Net MVC4, questo non aiuta poiché ci saranno viste parziali con i propri ViewModels e le sezioni parziale / Contenuto, non dovrebbero interferire tra loro e, a causa del rendering condizionale, sarà davvero difficile utilizzare questo approccio.
bhuvin,

1
@bhuvin usando <! - ko stopBinding: true -> ti aiuterà con quei modelli di viste multiple e sezioni di viste parziali. Vedi knockmeout.net/2012/05/quick-tip-skip-binding.html per maggiori informazioni.
Micaël Félix,

285

Knockout ora supporta l'associazione di più modelli. Ilko.applyBindings() metodo accetta un parametro facoltativo: l'elemento e i suoi discendenti a cui verrà attivata l'associazione.

Per esempio:

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

Ciò limita l'attivazione all'elemento con ID someElementIde i suoi discendenti.

Vedi la documentazione per maggiori dettagli.


72
Se desideri utilizzare un selettore jQuery, ti consigliamo di aggiungere [0]un elemento DOM effettivo (anziché l'oggetto jQuery) in questo modo:ko.applyBindings(myViewModel, $('#someElementId')[0])
MrBoJangles,

3
Questa dovrebbe essere la risposta accettata. È ancora possibile utilizzare un oggetto master come la risposta attualmente accettata, quindi associare i singoli modelli di visualizzazione ai loro elementi appropriati nella pagina. Ciò consentirà di risparmiare sulle prestazioni e limitare l'ambito necessario per il binding dei dati.
Kevin Heidt,

È possibile comunicare viewModels a vicenda con questo approccio? cioè ho TaskVM e NoteVM. L'attività può contenere note. Pertanto il mio TaskVM deve avere un array osservabile, ovvero note il cui tipo è TaskVM. Puoi condividere un esempio per un caso del genere?
Ahmet

Probabilmente è meglio fare domande sulla comunicazione tra VM in una nuova domanda.
Richard Nalezynski,

21

Questa è la mia risposta dopo aver completato un progetto molto ampio con molti ViewModels in vista singola.

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

Per questa vista sto creando 2 modelli di vista per id = container1 e id = container2 in due file javascript separati.

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

}

Quindi dopo questi 2 viewmodels si stanno registrando come viewmodels separati in 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"));
    }
});

In questo modo puoi aggiungere qualsiasi numero di viewmodel per div separati. Ma assicurati di non creare un modello di vista separato per un div all'interno di un div registrato.


È possibile fare un tipo di viewmodel all'interno dell'altro invece di essere elementi separati del DOM?
UserEsp

4

Controlla il plug-in MultiModels per Knockout JS - https://github.com/sergun/Knockout-MultiModels


6
Che vantaggio ha questo rispetto solo a ko.applyBindings (viewModel, document.getElementById ("divName"))? Non è solo zucchero sintattico?
Paolo del Mundo,

1
@Paolo del Mundo Aggiunge anche una dipendenza dal plugin LiveQuery.
Lars Gyrup Brink Nielsen,

@PaolodelMundo lo scopo del plug-in è quello di essere in grado di utilizzare una serie di modelli di visualizzazione in modo decentrante
Sergey Zwezdin,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.