KnockOutJS - Plusieurs modèles de vue dans une seule vue

201

Je pense que mon application devient assez grande maintenant, trop grande pour gérer chaque vue avec un seul ViewModel.

Je me demande donc à quel point il serait difficile de créer plusieurs ViewModels et de les charger tous dans une seule View. Avec une note que je dois également être en mesure de passer des données X ViewModel en données Y ViewModel afin que les ViewModels individuels doivent être en mesure de communiquer entre eux ou au moins de se connaître.

Par exemple, j'ai un <select>menu déroulant, ce menu déroulant de sélection a un état sélectionné qui me permet de passer l'ID de l'élément sélectionné dans le <select>à un autre appel Ajax dans un ViewModel séparé ....

Tous les points sur le traitement de nombreux ViewModels dans une seule vue sont appréciés :)

CLiown
la source
12
Pour ceux qui arrivent à cette question, veuillez faire défiler la réponse acceptée. Knockout prend désormais en charge plusieurs contextes de liaison . Il n'y a pas besoin d'un géant masterVM.
Carrie Kendall

Réponses:

150

S'ils doivent tous être sur la même page, un moyen simple de le faire est d'avoir un modèle de vue maître contenant un tableau (ou une liste de propriétés) des autres modèles de vue.

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

Ensuite, vous masterVMpouvez avoir d'autres propriétés si nécessaire, pour la page elle-même. La communication entre les modèles de vue ne serait pas difficile dans cette situation, car vous pourriez relayer via masterVM, ou vous pourriez utiliser les liaisons $parent/ $rootin, ou d'autres options personnalisées.

John Papa
la source
2
Alors serais-je capable de faire quelque chose comme: data-bind = "text: masterVM.vmA", je suppose que je pourrais toujours utiliser ko.applyBindings avec l'élément DOM attaché. Supposons que cela signifie également que je pourrais faire: data-bind = "$ parent.masterVm"?
CLiown
12
@CLiown Vous pouvez utiliser la with:liaison, vous ne vous
répéterez donc
4
@CLiown Oui, vous pouvez le faire si vous vous connectez au masterVM. Vous pouvez également utiliser la liaison "avec" pour éviter la syntaxe des points lorsque vous plongez dans les modèles de sous-vues.
John Papa
1
Je pense que cette approche est très restrictive ... Maintenant, dans mon cas, j'utilise ASP.Net MVC4, cela n'aide pas car il y aura des vues partielles ayant ses propres ViewModels, et les sections partielles / Contenu, ne devraient pas interférer les unes avec les autres , et en raison du rendu conditionnel, il sera très difficile d'utiliser cette approche.
bhuvin
1
@bhuvin en utilisant <! - ko stopBinding: true -> vous aidera avec ces modèles de vues multiples et sections de vues partielles. Voir knockmeout.net/2012/05/quick-tip-skip-binding.html pour plus d'informations.
Micaël Félix
285

Knockout prend désormais en charge la liaison de plusieurs modèles. La ko.applyBindings()méthode prend un paramètre facultatif - l'élément et ses descendants auxquels la liaison sera activée.

Par exemple:

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

Cela limite l'activation à l'élément avec ID someElementId et à ses descendants.

Voir la documentation pour plus de détails.

sanatgersappa
la source
72
Si vous souhaitez utiliser un sélecteur jQuery, vous voudrez ajouter [0]pour spécifier un élément DOM réel (au lieu de l'objet jQuery) comme ceci:ko.applyBindings(myViewModel, $('#someElementId')[0])
MrBoJangles
3
Cela devrait être la réponse acceptée. Vous pouvez toujours utiliser un objet maître comme la réponse actuellement acceptée, puis lier les différents modèles de vue à leurs éléments appropriés sur la page. Cela permettra d'économiser sur les performances et limitera la portée nécessaire pour la liaison de données.
Kevin Heidt du
Est-il possible de communiquer viewModels entre eux avec cette approche? c'est à dire que j'ai TaskVM et NoteVM. La tâche peut avoir des notes. Par conséquent, mon TaskVM doit avoir un tableau observable, à savoir des notes dont le type est TaskVM. Pouvez-vous partager un exemple pour un cas comme celui-là?
ahmet
Il est probablement préférable de poser des questions sur la communication entre les machines virtuelles dans une nouvelle question.
Richard Nalezynski
21

C'est ma réponse après avoir terminé un très grand projet avec beaucoup de ViewModels en vue unique.

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

Pour cette vue, je crée 2 modèles de vue pour id = container1 et id = container2 dans deux fichiers javascript distincts.

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

}

Ensuite, après l'enregistrement de ces 2 modèles de vue en tant que modèles de vue distincts dans 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"));
    }
});

De cette façon, vous pouvez ajouter un nombre illimité de modèles de vues pour des divisions distinctes. Mais assurez-vous de ne pas créer de modèle de vue séparé pour un div à l'intérieur d'un div enregistré.

Janith Widarshana
la source
Est-il possible de faire ce type de viewmodel à l'intérieur des autres au lieu d'être des éléments séparés du DOM?
UserEsp
4

Vérifiez le plugin MultiModels pour Knockout JS - https://github.com/sergun/Knockout-MultiModels

Sergey Zwezdin
la source
6
Quel avantage cela a-t-il sur seulement ko.applyBindings (viewModel, document.getElementById ("divName"))? N'est-ce pas juste du sucre syntaxique?
Paolo del Mundo
1
@Paolo del Mundo Il ajoute également une dépendance au plugin LiveQuery.
Lars Gyrup Brink Nielsen
@PaolodelMundo le but du plugin est de pouvoir utiliser un ensemble de modèles de vues de manière décalée
Sergey Zwezdin