¿Cómo depurar errores de enlace de plantilla para KnockoutJS?

199

Sigo teniendo problemas con los problemas de depuración en las plantillas KnockoutJS.

Digamos que quiero vincularme a una propiedad llamada " items" pero en la plantilla hago un error tipográfico y me vinculo a la propiedad (no existente) " item".

Usar el depurador de Chrome solo me dice:

"item" is not defined.

¿Existen herramientas, técnicas o estilos de codificación que me ayuden a obtener más información sobre el problema del enlace?

RogierBessem
fuente

Respuestas:

344

Una cosa que hago con bastante frecuencia cuando hay un problema con los datos disponibles en un determinado alcance es reemplazar la plantilla / sección con algo como:

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

O, si quieres una versión un poco más legible:

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

Esto escupirá los datos que se están vinculando en ese ámbito y le permitirá asegurarse de que está anidando las cosas adecuadamente.

Actualización: a partir de KO 2.1 , puede simplificarlo a:

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

Ahora los argumentos pasan a JSON.stringify.

RP Niemeyer
fuente
ohh Necesito hacer esta pregunta también. Se usó un fragmento de código complicado para consolar datos de registro Ahora es mucho más fácil.
AlfeG
3
Tengo que pensar más sobre consejos de depuración y tal vez hacer una publicación en el blog. Otra que viene a la mente es hacer suscripciones manuales contra observables u observables computados para observar el cambio de valores. Como si fuera algo nameobservablename.subscribe(function(newValue) { console.log("name", newValue); });
RP Niemeyer
1
Puede ser porque esta respuesta es relativamente antigua, pero ¿por qué no usar console.log y aprovechar toda la potencia del depurador para ver las propiedades de los objetos? Ver, por ejemplo: stackoverflow.com/a/16242988/647845
Dirk Boer el
1
@DirkBoer: usar console.log también puede ser una excelente manera. Sin foreachembargo, muchas veces quiero ver los datos al lado de mis elementos, como en un escenario, y me resulta más fácil ver en la página dentro del marcado renderizado relevante que tamizar a través de la consola. Solo depende de la situación. Algunos de mis pensamientos aquí: knockmeout.net/2013/06/… . Además, es posible que desee registrar una versión "limpia" en su enlace como console.log(ko.toJS(valueAccessor()).
RP Niemeyer
1
@RuneJeppesen - No estoy seguro de qué tipo de datos está serializando, pero algo como esto puede ayudar: knockmeout.net/2011/04/…
RP Niemeyer
61

Si está utilizando Chrome para el desarrollo, hay una extensión realmente excelente (con la que no estoy afiliado) llamada depurador de contexto de Knockoutjs que le muestra el contexto vinculante directamente en el panel Elementos de las Herramientas para desarrolladores.

Neverfox
fuente
3
Desearía que Firefox o Firebug tuvieran esto. Alguien sabe de tal cosa?
Patrick Szalapski el
Parece que el soporte se ha eliminado. Hace que Chrome se bloquee si utiliza una estructura compleja de enlace de datos. No ha trabajado para ninguno de mis proyectos durante aproximadamente un año.
Ártico
Lamento escucharlo, aunque hace mucho que pasé de KO a Ember.
neverfox
1
Funciona (principalmente) bien para mí, y tengo algunas estructuras realmente complejas. No lo he probado, pero en las Opciones para la extensión sugiere: "Si experimenta bloqueos, probablemente tenga un modelo de vista no serializable. Puede desactivar la serialización". Hay una casilla de verificación debajo del mensaje para deshabilitar esta función.
Grinn
enormemente útil al instante, ty.
Andrew
37

Defina un enlaceHandler una vez , en algún lugar de sus archivos de biblioteca de JavaScript.

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

que simplemente usarlo le gusta esto:

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

Ventajas

  • Use toda la potencia del depurador de Chrome, como Reveal en Elements Panel
  • No tiene que agregar elementos personalizados a su DOM, solo para depurar

ingrese la descripción de la imagen aquí

Dirk Boer
fuente
32

Encontré otro que puede ser útil. Estaba depurando algunos enlaces e intenté usar el ejemplo de Ryans. Recibí un error de que JSON encontró un bucle 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>

Pero, utilizando este enfoque, se reemplazó el valor de enlace de datos con lo siguiente:

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

Ahora, si hago clic en el elemento PRE mientras tengo abierta la ventana de depuración de Chrome, obtengo una ventana de variables de alcance muy bien llena.

Encontré una forma un poco mejor para ello:

<pre data-bind="text: ko.computed(function() { debugger; })"></pre>
RogierBessem
fuente
Realmente util. Estaba encontrando bucles circulares knockout y problemas de marcado de Razor usando <pre data-bind = "text: ko.toJSON ($ data, null, 2)"> </pre>. El <pre ... debugger> es una solución perfecta. Por alguna razón, las entradas de RAZOR como @ Html.CheckBox estaban rompiendo ko.toJSON.
Ártico
20

Guía paso por paso

  1. Para esta guía, utilizaremos uno de los ejemplos oficiales de KnockoutJS .
  2. Digamos que desea ver los datos detrás del segundo contacto (Sensei Miyagi).
  3. Haga clic derecho en el primer cuadro de entrada del segundo contacto (el que tiene el texto 'Sensei').
  4. Seleccione 'Inspeccionar elemento'. Se abrirá la Barra de herramientas para desarrolladores de Chrome.
  5. Abra la ventana de la consola de JavaScript. Puede acceder a la consola haciendo clic en el >=icono en la parte inferior izquierda de la barra de herramientas del desarrollador de Chrome, o abriendo la pestaña "Consola" en la barra de herramientas del desarrollador de Chrome, o presionando Ctrl+ Shift+J
  6. Escriba el siguiente comando y presione Entrar: ko.dataFor($0)
  7. Ahora debería ver los datos vinculados a la segunda fila. Puede expandir los datos presionando el pequeño triángulo a la izquierda del Objeto para navegar por el árbol de objetos.
  8. Escriba el siguiente comando y presione Entrar: ko.contextFor($0)
  9. Ahora debería ver un objeto complejo que contiene todo el contexto de Knockout, incluida la raíz y todos los padres. Esto es útil cuando está escribiendo expresiones de enlace complejas y desea experimentar con diferentes construcciones.

Ejemplo de salida al seguir la guía anterior

¿Qué es esta magia negra?

Este truco es una combinación de la función $ 0- $ 4 de Chrome y los métodos de utilidad de KnockoutJS . En resumen, Chrome recuerda que los elementos que ha seleccionado en la barra de herramientas para desarrolladores de Chrome y expone estos elementos bajo el alias $0, $1, $2, $3, $4. Por lo tanto, cuando hace clic con el botón derecho en un elemento de su navegador y selecciona 'Inspeccionar elemento', este elemento estará disponible automáticamente bajo el alias $0. Puedes usar este truco con KnockoutJS, AngularJS, jQuery o cualquier otro marco de JavaScript.

El otro lado del truco son los métodos de utilidad de KnockoutJS ko.dataFor y ko.contextFor:

  • ko.dataFor(element) - devuelve los datos que estaban disponibles para el enlace contra el elemento
  • ko.contextFor(element) - devuelve todo el contexto de enlace que estaba disponible para el elemento DOM.

Recuerde, la Consola JavaScript de Chrome es un entorno de tiempo de ejecución de JavaScript totalmente funcional. Esto significa que no está limitado a solo mirar las variables. Puede almacenar la salida ko.contextFory manipular el modelo de vista directamente desde la consola. Intenta var root = ko.contextFor($0).$root; root.addContact();ver qué pasa :-)

¡Feliz depuración!

Martin Devillers
fuente
7

Mira una cosa muy simple que uso:

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

O

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

Luego, en html, digamos que tenías:

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

Solo reemplácelo con

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

Más avanzado:

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

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

Disfruta :)

ACTUALIZAR

Otra cosa molesta es cuando intenta vincular a un valor indefinido. Imagine en el ejemplo anterior que el objeto de datos es simplemente {} no {valor: 'algún texto'}. En este caso, tendrás problemas, pero con el siguiente ajuste estarás bien:

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

La forma más fácil de ver qué datos se pasan al enlace es soltar los datos en la consola:

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

Knockout evaluará el valor para el enlace de texto (de hecho, cualquier enlace puede usarse aquí ) y vacía $ data al panel del navegador de la consola.

Dmitry Pavlov
fuente
2

Todas las otras respuestas funcionarán muy bien, solo estoy agregando lo que me gusta hacer:

En su vista (suponiendo que ya haya vinculado un ViewModel):

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

Código de eliminación:

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

Esto detendrá el código en el depurador elementy valueAccessor()contendrá información valiosa.

Aditya MP
fuente
no hay necesidad de un enlace personalizado. Eche un vistazo a stackoverflow.com/documentation/knockout.js/5066/…
Adam Wolski
1
Sí, estoy de acuerdo en que no hay una necesidad definitiva de hacerlo de esta manera, solo quería señalar que este es un estilo de depuración ... a todos parece gustarles hacerlo a su manera :)
Aditya MP
1

Si está desarrollando en Visual Studio e IE, me gusta más, data-bind="somebinding:(function(){debugger; return bindvalue; })()"me gusta más que la función echo, ya que irá al script con todos los enlaces en lugar del archivo eval y puede mirar los datos $ context $ (uso esto en Chrome también);

Filip Cordas
fuente
Apuesto a que no tiene nada que ver con Visual Studio o IE.
Serhiy
@Serhiy Lo mismo con Chrome pero en Chrome creo que podría acceder al archivo sin él. No creo que pueda acceder al archivo en VS.
Filip Cordas
0

Esto funciona para mi:

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