KnockOutJS - Vários ViewModels em uma única View

201

Eu estou pensando que meu aplicativo está ficando muito grande agora, muito grande para lidar com cada View com um único ViewModel.

Então, eu estou pensando em como seria difícil criar vários ViewModels e carregá-los em um único View. Com uma nota, eu também preciso passar dados do X ViewModel para o Y ViewModel para que os ViewModels individuais precisem se comunicar uns com os outros ou pelo menos estar cientes um do outro.

Por exemplo, eu tenho uma lista <select>suspensa, que selecione suspensa tem um estado selecionado que me permite passar o ID do item selecionado na <select>outra chamada do Ajax em um ViewModel separado ....

Todos os pontos em lidar com vários ViewModels em uma única visualização são apreciados :)

CLiown
fonte
12
Para quem chega a essa pergunta, role a resposta aceita. Nocaute agora suporta vários contextos de ligação . Não há necessidade de um gigante masterVM.
Carrie Kendall

Respostas:

150

Se todos eles precisarem estar na mesma página, uma maneira fácil de fazer isso é ter um modelo de vista principal contendo uma matriz (ou lista de propriedades) dos outros modelos de vista.

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

Em seguida, você masterVMpode ter outras propriedades, se necessário, para a própria página. A comunicação entre os modelos de visualização não seria difícil nesta situação, pois você poderia retransmitir através das ligações / masterVMou usar as ligações $parent/ $rootin ou algumas outras opções personalizadas.

John Papa
fonte
2
Assim, eu seria capaz de fazer algo como: data-bind = "text: masterVM.vmA", suponho que ainda possa usar o ko.applyBindings com o elemento DOM anexado. Suponha que isso também signifique que eu poderia fazer: data-bind = "$ parent.masterVm"?
Cliown
12
@CLiown Você pode usar with:bindging, então você não vai repetir-se
AlfeG
4
@CLiown Sim, você poderia fazer isso se ligasse ao masterVM. Você também pode usar a ligação "com" para ajudar a evitar a sintaxe do ponto ao mergulhar nos modelos de sub-visualização.
19412 John Papa João
1
Eu acho que essa abordagem é muito restritiva ... Agora, no meu caso, estou usando o ASP.Net MVC4, isso não ajuda, pois haverá visualizações parciais com seus próprios ViewModels e as seções parciais / Conteúdo, não devem interferir entre si e devido à renderização condicional Será realmente difícil usar essa abordagem.
bhuvin
1
@bhuvin usando <! - ko stopBinding: true -> irá ajudá-lo com vários modelos de visualização e seções de visualizações parciais. Consulte knockmeout.net/2012/05/quick-tip-skip-binding.html para obter mais informações.
Micaël Félix
285

Nocaute agora suporta vários modelos de ligação. O ko.applyBindings()método usa um parâmetro opcional - o elemento e seus descendentes aos quais a ligação será ativada.

Por exemplo:

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

Isso restringe a ativação ao elemento com ID someElementIde seus descendentes.

Veja a documentação para mais detalhes.

sanatgersappa
fonte
72
Se você deseja usar um seletor de jQuery, convém adicionar [0]para especificar um elemento DOM real (em vez do objeto jQuery) da seguinte forma:ko.applyBindings(myViewModel, $('#someElementId')[0])
MrBoJangles
3
Essa deve ser a resposta aceita. Você ainda pode usar um objeto mestre como a resposta atualmente aceita e vincular os modelos de exibição individuais aos seus elementos apropriados na página. Isso economizará desempenho e limita o escopo necessário para a ligação de dados.
Kevin Heidt
É possível comunicar os viewModels com essa abordagem? ou seja, eu tenho o TaskVM e o NoteVM. Tarefa pode ter notas. Portanto, meu TaskVM deve ter um observableArray, ou seja, notas cujo tipo é TaskVM. Você pode compartilhar um exemplo para um caso como esse?
ahmet 08/03
Provavelmente, é melhor perguntar sobre a comunicação entre VMs em uma nova pergunta.
Richard Nalezynski 10/10
21

Esta é a minha resposta depois de concluir um projeto muito grande com muitos ViewModels em exibição única.

Visualização em 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>

Para esta visualização, estou criando dois modelos de visualização para id = container1 e id = container2 em dois arquivos javascript separados.

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

}

Depois que esses dois viewmodels forem registrados como viewmodels separados no 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"));
    }
});

Assim, você pode adicionar qualquer número de modelos de exibição para divs separados. Mas certifique-se de não criar um modelo de vista separado para uma div dentro da div registrada.

Janith Widarshana
fonte
É possível fazer esse tipo de viewmodel dentro de outro para ser elementos separados do DOM?
usar o seguinte comando
4

Verifique o plug-in MultiModels para Knockout JS - https://github.com/sergun/Knockout-MultiModels

Sergey Zwezdin
fonte
6
Que vantagem isso tem sobre apenas ko.applyBindings (viewModel, document.getElementById ("divName"))? Não é apenas açúcar sintático?
Paolo del Mundo
1
@ Paolo del Mundo Também adiciona uma dependência do plug-in do LiveQuery.
Lars Gyrup Brink Nielsen
@PaolodelMundo o propósito do plugin é para ser capaz de usar conjunto de viewmodels em forma decalrative
Sergey Zwezdin