wake-up-neo.com

Wie debuggen Sie Vorlagenbindungsfehler für KnockoutJS

Ich habe immer Probleme mit dem Debuggen von Problemen in KnockoutJS-Vorlagen.

Angenommen, ich möchte an eine Eigenschaft namens "items" binden, aber in der Vorlage mache ich einen Tippfehler und binde an die (nicht vorhandene) Eigenschaft "item".

Die Verwendung des Chrome-Debuggers sagt mir nur:

"item" is not defined.

Gibt es Werkzeuge, Techniken oder Codierungsstile, mit denen ich mehr Informationen zum Bindungsproblem erhalten kann?

196
RogierBessem

Was ich oft mache, wenn es Probleme gibt, welche Daten in einem bestimmten Umfang verfügbar sind, ist das Ersetzen der Vorlage/des Abschnitts durch Folgendes:

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

Oder wenn Sie eine etwas lesbarere Version wünschen:

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

Dadurch werden die Daten, die an diesen Bereich gebunden sind, ausgespuckt und Sie können sicherstellen, dass Sie die Objekte ordnungsgemäß verschachteln. 

Update: Ab KO 2.1 können Sie es vereinfachen auf:

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

Nun werden die Argumente an JSON.stringify übergeben.

338
RP Niemeyer

Wenn Sie Chrome für die Entwicklung verwenden, gibt es eine wirklich großartige Erweiterung (mit der ich nicht verbunden bin) namens Knockoutjs context debugger , die Ihnen den Bindungskontext direkt in der Elementpalette der Developer Tools anzeigt.

60
neverfox

Definiere einmal einen bindingHandler irgendwo in deinen JavaScript-Bibliotheksdateien.

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

als einfach verwenden sie es gerne:

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

Vorteile

  • Nutzen Sie die volle Leistung des Chrome-Debuggers wie Reveal in Elements Panel.
  • Sie müssen keine benutzerdefinierten Elemente zu Ihrem DOM hinzufügen, nur zum Debuggen

enter image description here

35
Dirk Boer

Ich habe eine andere gefunden, die hilfreich sein kann. Ich debuggte einige Bindungen und versuchte es mit Ryans Beispiel. Ich habe einen Fehler erhalten, dass JSON eine Kreisschleife gefunden hat.

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

Bei diesem Ansatz wurde jedoch der Wert für die Datenbindung durch Folgendes ersetzt:

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

Wenn ich jetzt auf das PRE-Element klicke, während das Chrome-Debug-Fenster geöffnet ist, erhalte ich ein schön gefülltes Oszilloskop-Fenster.

Einen etwas besseren Weg dafür gefunden:

<pre data-bind="text: ko.computed(function() { debugger; })"></pre>
32
RogierBessem

Schritt für Schritt Anleitung

  1. Für diesen Leitfaden verwenden wir eines der offiziellen KnockoutJS-Beispiele .
  2. Angenommen, Sie möchten die Daten hinter dem zweiten Kontakt (Sensei Miyagi) sehen.
  3. Klicken Sie mit der rechten Maustaste auf das erste Eingabefeld des zweiten Kontakts (das mit dem Text 'Sensei').
  4. Wählen Sie "Element prüfen". Die Chrome Developer Toolbar wird geöffnet.
  5. Öffnen Sie das JavaScript-Konsolenfenster. Sie können auf die Konsole zugreifen, indem Sie unten links in der Chrome Developer Toolbar auf das Symbol >= klicken oder in der Chrome Developer Toolbar auf die Registerkarte "Konsole" klicken oder auf drücken Ctrl+Shift+J
  6. Geben Sie den folgenden Befehl ein und drücken Sie die Eingabetaste: ko.dataFor($0)
  7. Sie sollten jetzt die Daten sehen, die an die zweite Zeile gebunden sind. Sie können die Daten erweitern, indem Sie auf das kleine Dreieck links neben dem Objekt drücken, um im Objektbaum zu navigieren.
  8. Geben Sie den folgenden Befehl ein und drücken Sie die Eingabetaste: ko.contextFor($0)
  9. Sie sollten jetzt ein komplexes Objekt sehen, das den gesamten Knockout-Kontext einschließlich des Stamms und aller übergeordneten Objekte enthält. Dies ist nützlich, wenn Sie komplexe Bindungsausdrücke schreiben und mit verschiedenen Konstrukten experimentieren möchten.

Example output when following above guide

Was ist diese schwarze Magie?

Dieser Trick ist eine Kombination aus Chrome's $ 0- $ 4-Funktion und KnockoutJS's Utility-Methoden . Kurz gesagt, Chrome merkt sich, welche Elemente Sie in der Chrome Developer Toolbar ausgewählt haben, und macht diese Elemente unter dem Alias ​​$0, $1, $2, $3, $4 verfügbar. Wenn Sie mit der rechten Maustaste auf ein Element in Ihrem Browser klicken und "Inspect element" auswählen, wird dieses Element automatisch unter dem Alias ​​$0 verfügbar. Sie können diesen Trick mit KnockoutJS, AngularJS, jQuery oder jedem anderen JavaScript-Framework verwenden.

Die andere Seite des Tricks sind die Dienstprogrammmethoden ko.dataFor und ko.contextFor von KnockoutJS:

  • ko.dataFor(element) - gibt die Daten zurück, die für die Bindung an das Element verfügbar waren
  • ko.contextFor(element) - gibt den gesamten Bindungskontext zurück, der für das DOM-Element verfügbar war.

Beachten Sie, dass die JavaScript-Konsole von Chrome eine voll funktionsfähige JavaScript-Laufzeitumgebung ist. Dies bedeutet, dass Sie sich nicht nur auf Variablen beschränken müssen. Sie können die Ausgabe von ko.contextFor speichern und das Ansichtsmodell direkt von der Konsole aus bearbeiten. Probiere var root = ko.contextFor($0).$root; root.addContact(); und schau was passiert :-)

Viel Spaß beim Debuggen!

17

Schauen Sie sich ein wirklich einfaches Ding an, das ich verwende:

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

Oder 

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

Dann hatten Sie in html:

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

Ersetzen Sie es einfach durch

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

Fortgeschrittener:

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

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

Genießen :)

UPDATE

Ärgerlich ist auch, wenn Sie versuchen, sich an einen undefinierten Wert zu binden. Stellen Sie sich im obigen Beispiel vor, dass das Datenobjekt nur {} und nicht {value: 'some text'} ist. In diesem Fall werden Sie in Schwierigkeiten geraten, aber mit dem folgenden Tweak geht es Ihnen gut:

<div data-bind="text: $data['value']"></div> 
7
Aleksey Bykov

Ich habe ein Github-Projekt mit dem Namen knockthrough.js erstellt, um diese Fehler zu visualisieren.

https://github.com/JonKragh/knockthrough

Es hebt Bindungsfehler hervor und gibt einen Dump des Datenkontextes auf diesem Knoten aus.

Sie können hier mit einem Beispiel spielen: http://htmlpreview.github.io/?https://github.com/JonKragh/knockthrough/blob/master/default.htm

enter image description here

Dank an RP Niemeyer für seine hervorragenden Knockout-Code-Beispiele auf SO, um mich an diesen Punkt zu bringen.

5
Jon Kragh

Der einfachste Weg, um zu sehen, welche Daten an die Bindung übergeben werden, ist das Ablegen der Daten auf der Konsole:

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

Knockout wertet den Wert für die Textbindung aus (jede Bindung kann hier tatsächlich verwendet werden) und leert $ data in das Konsolenbrowser-Panel.

3
Dmitry Pavlov

Wenn Sie in Visual Studio und IE entwickeln, gefällt mir das mehr data-bind="somebinding:(function(){debugger; return bindvalue; })()". Ich mag es mehr als die Echo-Funktion, da es mit allen Bindungen zum Skript geht und nicht die eval-Datei $ data (ich verwende dies auch in Chrome);

1
Filip Cordas

Alle anderen Antworten werden großartig funktionieren. Ich füge nur hinzu, was ich gerne mache:

In Ihrer Ansicht (vorausgesetzt, Sie haben bereits ein ViewModel gebunden):

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

Knockout-Code:

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

Dadurch wird der Code im Debugger angehalten, und element und valueAccessor() enthalten wertvolle Informationen.

1
Aditya M P

Das funktioniert für mich: 

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