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?
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.
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.
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
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>
>=
klicken oder in der Chrome Developer Toolbar auf die Registerkarte "Konsole" klicken oder auf drücken Ctrl+Shift+Jko.dataFor($0)
ko.contextFor($0)
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 warenko.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!
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>
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
Dank an RP Niemeyer für seine hervorragenden Knockout-Code-Beispiele auf SO, um mich an diesen Punkt zu bringen.
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.
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);
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.
Das funktioniert für mich:
<div data-bind="text: function(){ debugger; }()"></div>