Estou criando uma funcionalidade em uma página da web que o usuário pode executar várias vezes. Por meio da ação do usuário, um objeto / modelo é criado e aplicado ao HTML usando ko.applyBindings ().
O HTML vinculado a dados é criado por meio de modelos jQuery.
Por enquanto, tudo bem.
Quando repito esta etapa criando um segundo objeto / modelo e chamo ko.applyBindings (), encontro dois problemas:
- A marcação mostra o objeto / modelo anterior, bem como o novo objeto / modelo.
- Um erro de javascript ocorre relacionado a uma das propriedades no objeto / modelo, embora ainda seja renderizado na marcação.
Para contornar esse problema, após a primeira passagem, chamo .empty () do jQuery para remover o HTML modelado que contém todos os atributos de vinculação de dados, de modo que não esteja mais no DOM. Quando o usuário inicia o processo para a segunda passagem, o HTML vinculado a dados é adicionado novamente ao DOM.
Mas, como eu disse, quando o HTML é adicionado novamente ao DOM e vinculado ao novo objeto / modelo, ele ainda inclui dados do primeiro objeto / modelo e ainda recebo o erro JS que não ocorre durante a primeira passagem.
A conclusão parece ser que Knockout está mantendo essas propriedades vinculadas, mesmo que a marcação seja removida do DOM.
Então, o que estou procurando é um meio de remover essas propriedades associadas do Knockout; dizendo ao nocaute que não há mais um modelo observável. Existe uma maneira de fazer isso?
EDITAR
O processo básico é que o usuário carregue um arquivo; o servidor responde com um objeto JSON, o HTML vinculado a dados é adicionado ao DOM e o modelo de objeto JSON é vinculado a este HTML usando
mn.AccountCreationModel = new AccountViewModel(jsonData.Account);
ko.applyBindings(mn.AccountCreationModel);
Depois que o usuário fez algumas seleções no modelo, o mesmo objeto é postado de volta no servidor, o HTML vinculado a dados é removido do DOM e eu tenho o seguinte JS
mn.AccountCreationModel = null;
Quando o usuário deseja fazer isso mais uma vez, todas essas etapas são repetidas.
Receio que o código esteja muito "envolvido" para fazer uma demonstração do jsFiddle.
init
função na qual você passa os dados a serem aplicados?Respostas:
Você já tentou chamar o método de nó limpo do knockout em seu elemento DOM para descartar os objetos vinculados à memória?
Em seguida, aplicar as ligações knockout novamente apenas naquele elemento com seus novos modelos de visualização atualizaria sua ligação de visualização.
fonte
delete
certas chaves nos próprios elementos dom, que aparentemente é onde toda a magia nocauteadora está armazenada. Se alguém tiver uma fonte de documentação, ficaria muito grato.Para um projeto no qual estou trabalhando, escrevi uma
ko.unapplyBindings
função simples que aceita um nó jQuery e o booleano remove. Primeiro, ele desassocia todos os eventos jQuery, já que oko.cleanNode
método não cuida disso. Testei vazamentos de memória e parece funcionar bem.fonte
ko.cleanNode()
chamado e nem todo o html foi substituído.Você pode tentar usar o com vinculação que o knockout oferece: http://knockoutjs.com/documentation/with-binding.html A ideia é usar aplicar vinculações uma vez e, sempre que seus dados forem alterados, apenas atualize seu modelo.
Digamos que você tenha um modelo de visualização de nível superior storeViewModel, seu carrinho representado por cartViewModel e uma lista de itens nesse carrinho - digamos, cartItemsViewModel.
Você vincularia o modelo de nível superior - storeViewModel a toda a página. Em seguida, você pode separar as partes de sua página que são responsáveis pelo carrinho ou itens do carrinho.
Vamos supor que cartItemsViewModel tenha a seguinte estrutura:
O cartItemsViewModel pode estar vazio no início.
As etapas seriam assim:
Defina ligações em html. Separe a ligação cartItemsViewModel.
O modelo de loja vem do seu servidor (ou é criado de qualquer outra forma).
var storeViewModel = ko.mapping.fromJS(modelFromServer)
Defina modelos vazios em seu modelo de vista de nível superior. Em seguida, uma estrutura desse modelo pode ser atualizada com os dados reais.
Vincule o modelo de vista de nível superior.
ko.applyBindings(storeViewModel);
Quando o objeto cartItemsViewModel estiver disponível, atribua-o ao espaço reservado previamente definido.
storeViewModel.cartItemsViewModel(actualCartItemsModel);
Se você gostaria de limpar os itens do carrinho:
storeViewModel.cartItemsViewModel(null);
Knockout cuidará do html - ou seja, aparecerá quando o modelo não estiver vazio e o conteúdo de div (aquele com "com ligação") desaparecerá.
fonte
Tenho que chamar ko.applyBinding cada vez que clica no botão de pesquisa e os dados filtrados são retornados do servidor e, neste caso, o trabalho seguinte para mim sem usar ko.cleanNode.
Eu experimentei, se substituirmos foreach por template, ele deve funcionar bem no caso de coleções / observableArray.
Você pode achar este cenário útil.
fonte
Em vez de usar as funções internas do KO e lidar com a remoção do manipulador de eventos do JQuery, uma ideia muito melhor é usar
with
outemplate
ligações. Quando você faz isso, ko recria essa parte do DOM e, portanto, ela é automaticamente limpa. Essa também é a forma recomendada, veja aqui: https://stackoverflow.com/a/15069509/207661 .fonte
Acho que seria melhor manter a vinculação o tempo todo e simplesmente atualizar os dados associados a ela. Eu encontrei esse problema e descobri que apenas chamar usando o
.resetAll()
método no array no qual eu estava mantendo meus dados era a maneira mais eficaz de fazer isso.Basicamente, você pode começar com alguma var global que contém dados a serem renderizados por meio do ViewModel:
Levei um tempo para perceber que não podia simplesmente fazer
myLiveData
um array normal - ako.oberservableArray
parte era importante.Então você pode ir em frente e fazer o que quiser
myLiveData
. Por exemplo, faça uma$.getJSON
chamada:Depois de fazer isso, você pode prosseguir e aplicar vinculações usando seu ViewModel como de costume:
Então, no HTML, use
myData
como faria normalmente.Dessa forma, você pode simplesmente muck com myLiveData de qualquer função. Por exemplo, se você deseja atualizar a cada poucos segundos, basta envolver essa
$.getJSON
linha em uma função e chamásetInterval
-la. Você nunca precisará remover a ligação, desde que se lembre de manter amyLiveData.removeAll();
linha dentro.A menos que seus dados sejam realmente enormes, o usuário não será capaz de perceber o tempo entre a reconfiguração do array e a adição dos dados mais atuais de volta.
fonte
Eu tive um problema de vazamento de memória recentemente e
ko.cleanNode(element);
não faria isso por mim -ko.removeNode(element);
fez. Javascript + Knockout.js vazamento de memória - Como ter certeza de que o objeto está sendo destruído?fonte
Você já pensou sobre isso:
Eu vim com isso porque no Knockout, encontrei este código
Então, para mim, não é realmente um problema que já esteja vinculado, é que o erro não foi detectado e corrigido ...
fonte
Eu descobri que se o modelo de visão contém muitas ligações div, a melhor maneira de limpar o
ko.applyBindings(new someModelView);
é usar:ko.cleanNode($("body")[0]);
Isso permite que você chame um novoko.applyBindings(new someModelView2);
dinamicamente sem a preocupação de o modelo de visão anterior ainda estar vinculado.fonte
$("body")[0]
édocument.body
.