Como depurar erros de ligação de modelo para KnockoutJS?

199

Continuo tendo problemas com problemas de depuração nos modelos do KnockoutJS.

Digamos que eu queira vincular a uma propriedade chamada " items", mas no modelo eu digitei um erro de digitação e vinculei à propriedade (não existente) " item".

O uso do depurador do Chrome diz apenas:

"item" is not defined.

Existem ferramentas, técnicas ou estilos de codificação que me ajudam a obter mais informações sobre o problema de ligação?

RogierBessem
fonte

Respostas:

344

Uma coisa que faço frequentemente quando há um problema com quais dados estão disponíveis em um determinado escopo é substituir o modelo / seção por algo como:

<div data-bind="text: ko.toJSON($data)"></div>

Ou, se você quiser uma versão um pouco mais legível:

<pre data-bind="text: JSON.stringify(ko.toJS($data), null, 2)"></pre>

Isso cuspirá os dados que estão sendo vinculados nesse escopo e permitirá que você aninhe as coisas adequadamente.

Atualização: a partir do KO 2.1 , você pode simplificá-lo para:

<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>

Agora os argumentos são passados ​​para JSON.stringify.

RP Niemeyer
fonte
ohh Eu preciso fazer essa pergunta também. Utilizou um código complicado para os dados do console.log. Agora é muito mais fácil.
AlfeG
3
Eu tenho que pensar mais sobre dicas de depuração e talvez fazer uma postagem no blog. Outro que vem à mente é fazer assinaturas manuais contra observáveis ​​ou observáveis ​​computados para observar os valores mudarem. Como se nameé um observável fazendoname.subscribe(function(newValue) { console.log("name", newValue); });
RP Niemeyer
1
Pode ser que essa resposta seja relativamente antiga, mas por que não usar o console.log e usar todo o poder do depurador para exibir as propriedades do objeto? Veja ie: stackoverflow.com/a/16242988/647845
Dirk Boer
1
@DirkBoer - usar console.log também pode ser uma ótima maneira. Muitas vezes, quero ver os dados ao lado dos meus elementos, como em um foreachcenário, e acho mais fácil ver na página a marcação renderizada relevante do que vasculhar o console. Depende apenas da situação. Um pouco mais dos meus pensamentos aqui: knockmeout.net/2013/06// . Além disso, você pode querer registrar uma versão "limpa" em sua ligação como console.log(ko.toJS(valueAccessor()).
RP Niemeyer
1
@RuneJeppesen - Não tenho a certeza que tipo de dados que está a serialização, mas algo como isto pode ajudar: knockmeout.net/2011/04/...
RP Niemeyer
61

Se você estiver usando o Chrome para desenvolvimento, há uma grande extensão (com a qual eu não sou afiliado) chamada depurador de contexto Knockoutjs que mostra o contexto de ligação diretamente no painel Elementos das Ferramentas do desenvolvedor.

neverfox
fonte
3
Eu gostaria que o Firefox ou Firebug tivessem isso. Alguém sabe de uma coisa dessas?
Patrick Szalapski
Aparece suporte foi descartado. Faz com que o chrome falhe se você usar uma estrutura complexa de ligação de dados. Não trabalha em nenhum dos meus projetos há cerca de um ano.
Arctic
Lamento ouvi-lo, embora eu já tenha passado de KO para Ember.
neverfox 31/01
1
Funciona (principalmente) para mim, e eu tenho algumas estruturas realmente complexas. Eu não tentei, mas nas Opções para a extensão, sugere: "Se houver falhas, é provável que você tenha um modelo de exibição não serializável. Você pode desativar a serialização". Há uma caixa de seleção abaixo da mensagem para desativar esse recurso.
Grinn #
extremamente útil instantaneamente, ty.
Andrew Andrew
37

Defina um bindingHandler uma vez , em algum lugar nos arquivos da biblioteca JavaScript.

ko.bindingHandlers.debug = 
{
    init: function(element, valueAccessor) 
    {
        console.log( 'Knockoutbinding:' );
        console.log( element );
        console.log( ko.toJS(valueAccessor()) );
    }
};

do que simplesmente usá-lo assim:

<ul data-bind="debug: $data">

Vantagens

  • Use toda a potência do depurador do Chrome, como Revelar no Painel de elementos
  • Você não precisa adicionar elementos personalizados ao seu DOM, apenas para depuração

insira a descrição da imagem aqui

Dirk Boer
fonte
32

Encontrei outro que pode ser útil. Eu estava depurando algumas ligações e tentei usar o exemplo do Ryans. Eu recebi um erro que o JSON encontrou um loop circular.

<ul class="list list-fix" data-bind="foreach: detailsView().tabs">
 <li>
   <pre data-bind="text: JSON.stringify(ko.toJS($parent), null, 2)"></pre>
   <a href="#" data-bind="click: $parent.setActiveTab, text: title"></a>
 </li>
</ul>

Mas, usando essa abordagem, a substituiu o valor de ligação de dados pelo seguinte:

  <ul class="list list-fix" data-bind="foreach: detailsView().tabs">
    <li>
      <pre data-bind="text: 'click me', click: function() {debugger}"></pre>
      <a href="#" data-bind="click: $parent.setActiveTab, text: title"></a>
    </li>
  </ul>

Agora, se eu clicar no elemento PRE enquanto a janela de depuração do Chrome estiver aberta, recebo uma janela de variáveis ​​de escopo bem preenchida.

Encontrei uma maneira um pouco melhor para isso:

<pre data-bind="text: ko.computed(function() { debugger; })"></pre>
RogierBessem
fonte
Muito útil. Encontrava loops circulares vazados e problemas de marcação do Razor usando <pre data-bind = "text: ko.toJSON ($ data, null, 2)"> </pre>. O <pre ... debugger> é uma solução perfeita. Por alguma razão, entradas RAZOR como @ Html.CheckBox estavam quebrando o ko.toJSON.
Arctic ártico
20

Guia passo a passo

  1. Para este guia, usaremos um dos exemplos oficiais do KnockoutJS .
  2. Digamos que você queira ver os dados por trás do segundo contato (Sensei Miyagi).
  3. Clique com o botão direito do mouse na primeira caixa de entrada do segundo contato (aquele com o texto 'Sensei').
  4. Selecione 'Inspecionar elemento'. A barra de ferramentas do desenvolvedor do Chrome será aberta.
  5. Abra a janela do console do JavaScript. Você pode acessar o console clicando no >=ícone no canto inferior esquerdo da barra de ferramentas do desenvolvedor do Chrome ou abrindo a guia "Console" na barra de ferramentas do desenvolvedor do Chrome ou pressionando Ctrl+ Shift+J
  6. Digite o seguinte comando e pressione Enter: ko.dataFor($0)
  7. Agora você deve ver os dados que estão vinculados à segunda linha. Você pode expandir os dados pressionando o pequeno triângulo à esquerda do objeto para navegar na árvore de objetos.
  8. Digite o seguinte comando e pressione Enter: ko.contextFor($0)
  9. Agora você deve ver um objeto complexo que contém todo o contexto do Knockout, incluindo a raiz e todos os pais. Isso é útil quando você está escrevendo expressões de ligação complexas e deseja experimentar diferentes construções.

Exemplo de saída ao seguir o guia acima

O que é essa magia negra?

Esse truque é uma combinação do recurso de US $ 0 a US $ 4 do Chrome e dos métodos utilitários do KnockoutJS . Em suma, o Chrome se lembra de quais elementos você tenha selecionado no Developer Chrome Toolbar e expõe esses elementos sob o pseudônimo $0, $1, $2, $3, $4. Portanto, quando você clica com o botão direito do mouse em um elemento do navegador e seleciona 'Inspecionar elemento', esse elemento fica automaticamente disponível sob o alias$0 . Você pode usar esse truque com KnockoutJS, AngularJS, jQuery ou qualquer outra estrutura JavaScript.

O outro lado do truque são os métodos utilitários do KnockoutJS, ko.dataFor e ko.contextFor:

  • ko.dataFor(element) - retorna os dados que estavam disponíveis para ligação com o elemento
  • ko.contextFor(element) - retorna todo o contexto de ligação que estava disponível para o elemento DOM.

Lembre-se, o JavaScript Console do Chrome é um ambiente de tempo de execução JavaScript totalmente funcional. Isso significa que você não está limitado apenas a olhar para variáveis. Você pode armazenar a saída ko.contextFore manipular o viewmodel diretamente do console. Experimentarvar root = ko.contextFor($0).$root; root.addContact(); e veja o que acontece :-)

Feliz depuração!

Martin Devillers
fonte
7

Confira uma coisa realmente simples que eu uso:

function echo(whatever) { debugger; return whatever; }

Ou

function echo(whatever) { console.log(whatever); return whatever; }

Então, em html, digamos, você tinha:

<div data-bind="text: value"></div>

Apenas substitua-o por

<div data-bind="text: echo(value)"></div>

Mais avancado:

function echo(vars, member) { console.log(vars); debugger; return vars[0][member]; }

<div data-bind="text: echo([$data, $root, $parents, $parentContext], 'value')"></div>

Aproveitar :)

ATUALIZAR

Outra coisa irritante é quando você está tentando vincular a um valor indefinido. Imagine no exemplo acima que o objeto de dados é apenas {} não {value: 'some text'}. Nesse caso, você estará com problemas, mas com o seguinte ajuste você estará bem:

<div data-bind="text: $data['value']"></div> 
Trident D'Gao
fonte
3

A maneira mais fácil de ver quais dados são passados ​​para a ligação é soltá-los no console:

<div data-bind="text: console.log($data)"></div>

O knockout avaliará o valor da ligação de texto ( qualquer ligação pode ser usada aqui de fato ) e libera $ data no painel do navegador do console.

Dmitry Pavlov
fonte
2

Todas as outras respostas funcionarão muito bem, estou apenas adicionando o que gosto de fazer:

Na sua opinião (supondo que você já tenha vinculado um ViewModel):

<div data-bind="debugger: $data"></div>

Código de nocaute:

ko.bindingHandlers.debugger = {
    init: function (element, valueAccessor) {
        debugger;
    }
}

Isso fará uma pausa no código no depurador elemente valueAccessor()conterá informações valiosas.

Aditya MP
fonte
não há necessidade de uma ligação personalizada. Dê uma olhada em stackoverflow.com/documentation/knockout.js/5066/…
Adam Wolski
1
Sim, eu concordo que não há uma necessidade definitiva de fazê-lo dessa maneira, eu apenas queria salientar que este é um estilo de depuração ... todo mundo parece gostar de fazê-lo à sua maneira :) :)
Aditya MP
1

Se você está desenvolvendo no Visual studio e no IE, eu gosto mais data-bind="somebinding:(function(){debugger; return bindvalue; })()"disso, mais a função echo, pois ele irá para o script com todas as ligações, e não o arquivo eval, e você pode apenas olhar para os dados $ context $ (eu uso isso também no Chrome);

Filip Cordas
fonte
Aposto que não tem nada a ver com o Visual Studio ou o IE.
Serhiy
@ Serhiy Mesmo com o Chrome, mas no Chrome, acho que você pode acessar o arquivo sem ele. Acho que não pode acessar o arquivo no VS.
Filip Cordas
0

Isso funciona para mim:

<div data-bind="text: function(){ debugger; }()"></div>
Robert J
fonte