Wie debugge ich Vorlagenbindungsfehler für KnockoutJS?

199

Ich habe immer wieder Probleme beim 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 Tools, Techniken oder Codierungsstile, mit denen ich weitere Informationen zum Bindungsproblem erhalten kann?

RogierBessem
quelle

Antworten:

344

Eine Sache, die ich ziemlich oft mache, wenn es ein Problem mit den verfügbaren Daten in einem bestimmten Bereich gibt, ist, die Vorlage / den Abschnitt durch Folgendes zu ersetzen:

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

Oder wenn Sie eine etwas besser lesbare Version wünschen:

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

Dadurch werden die Daten ausgespuckt, die in diesem Bereich gebunden werden, und Sie können sicherstellen, dass Sie die Dinge ordnungsgemäß verschachteln.

Update: Ab KO 2.1 können Sie es vereinfachen, um:

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

Nun werden die Argumente an weitergeleitet JSON.stringify.

RP Niemeyer
quelle
ohh. Ich muss diese Frage auch stellen. Verwendeter komplizierter Code für console.log-Daten. Jetzt ist es viel einfacher.
AlfeG
3
Ich muss mehr über Debugging-Tipps nachdenken und vielleicht einen Blog-Beitrag schreiben. Eine andere Möglichkeit ist das manuelle Abonnieren von Observablen oder berechneten Observablen, um zu beobachten, wie sich Werte ändern. Als ob namees ein beobachtbares Tun istname.subscribe(function(newValue) { console.log("name", newValue); });
RP Niemeyer
1
Könnte daran liegen, dass diese Antwort relativ alt ist, aber warum nicht console.log verwenden und die volle Leistung des Debuggers zum Anzeigen von Objekteigenschaften nutzen? Siehe zB
Dirk Boer
1
@DirkBoer - die Verwendung von console.log kann auch eine großartige Möglichkeit sein. Oft möchte ich die Daten neben meinen Elementen sehen, wie in einem foreachSzenario, und ich finde es einfacher, sie auf der Seite innerhalb des relevanten gerenderten Markups zu sehen, als die Konsole zu durchsuchen. Kommt nur auf die Situation an. Noch ein paar meiner Gedanken hier: knockmeout.net/2013/06/… . Möglicherweise möchten Sie auch eine "saubere" Version in Ihrer Bindung wie protokollieren console.log(ko.toJS(valueAccessor()).
RP Niemeyer
1
@ RunJeppesen - Ich bin nicht sicher, welche Art von Daten Sie serialisieren, aber so etwas kann helfen: knockmeout.net/2011/04/…
RP Niemeyer
61

Wenn Sie Chrome für die Entwicklung verwenden, gibt es eine wirklich großartige Erweiterung (mit der ich nicht verbunden bin) namens Knockoutjs Kontextdebugger , die Ihnen den Bindungskontext direkt im Elementfenster der Entwicklertools anzeigt.

Neverfox
quelle
3
Ich wünschte, Firefox oder Firebug hätten das. Kennt jemand so etwas?
Patrick Szalapski
Die Unterstützung wurde anscheinend eingestellt. Verursacht einen Absturz von Chrome, wenn Sie eine komplexe Datenbindungsstruktur verwenden. Hat seit ungefähr einem Jahr für keines meiner Projekte gearbeitet.
Arktis
Es tut mir leid, das zu hören, obwohl ich längst von KO zu Ember gewechselt bin.
Neverfox
1
Es funktioniert (meistens) gut für mich und ich habe einige wirklich komplexe Strukturen. Ich habe es nicht ausprobiert, aber in den Optionen für die Erweiterung wird vorgeschlagen: "Wenn es zu Abstürzen kommt, haben Sie wahrscheinlich ein nicht serialisierbares Ansichtsmodell. Sie können die Serialisierung deaktivieren." Unter der Meldung befindet sich ein Kontrollkästchen zum Deaktivieren dieser Funktion.
Grinn
Sofort sehr nützlich, ty.
Andrew
37

Definieren Sie einen BindingHandler einmal irgendwo in Ihren JavaScript-Bibliotheksdateien.

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

als einfach zu benutzen mag es so:

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

Vorteile

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

Geben Sie hier die Bildbeschreibung ein

Dirk Boer
quelle
32

Ich habe eine andere gefunden, die hilfreich sein kann. Ich habe einige Bindungen getestet und versucht, Ryans Beispiel zu verwenden. Ich habe die Fehlermeldung erhalten, dass JSON eine kreisförmige Schleife 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 Verwendung dieses Ansatzes wurde der Datenbindungswert jedoch durch den folgenden 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 gut gefülltes Fenster mit Bereichsvariablen.

Einen besseren Weg dafür gefunden:

<pre data-bind="text: ko.computed(function() { debugger; })"></pre>
RogierBessem
quelle
Sehr nützlich. Bei der Verwendung von <pre data-bind = "text: ko.toJSON ($ data, null, 2)"> </ pre> sind Knockout-Kreisschleifen und Razor-Markup-Probleme aufgetreten. Der <Pre ... Debugger> ist eine perfekte Problemumgehung. Aus irgendeinem Grund brachen RAZOR-Eingaben wie @ Html.CheckBox ko.toJSON.
Arktis
20

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 auf das >=Symbol unten links in der Chrome Developer-Symbolleiste klicken oder die Registerkarte "Konsole" in der Chrome Developer-Symbolleiste öffnen oder Ctrl+ Shift+ drückenJ
  6. Geben Sie den folgenden Befehl ein und drücken Sie die Eingabetaste: ko.dataFor($0)
  7. Sie sollten nun 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 Elemente enthält. Dies ist nützlich, wenn Sie komplexe Bindungsausdrücke schreiben und mit verschiedenen Konstrukten experimentieren möchten.

Beispielausgabe, wenn Sie der obigen Anleitung folgen

Was ist das für schwarze Magie?

Dieser Trick ist eine Kombination aus der Funktion $ 0- $ 4 von Chrome und den Dienstprogrammmethoden von KnockoutJS . Kurz gesagt, Chrome merkt sich, welche Elemente Sie in der Chrome - Entwickler ausgewählt haben Toolbar und setzt diese Elemente unter dem Alias $0, $1, $2, $3, $4. Wenn Sie also mit der rechten Maustaste auf ein Element in Ihrem Browser klicken und "Element überprüfen" auswählen, wird dieses Element automatisch unter dem Alias ​​verfügbar $0. Sie können diesen Trick mit KnockoutJS, AngularJS, jQuery oder einem 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.

Denken Sie daran, 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 des ko.contextForAnsichtsmodells direkt von der Konsole aus speichern und bearbeiten. Versuche zu var root = ko.contextFor($0).$root; root.addContact();sehen, was passiert :-)

Viel Spaß beim Debuggen!

Martin Devillers
quelle
7

Schauen Sie sich eine wirklich einfache Sache an, die ich benutze:

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

AKTUALISIEREN

Eine andere ärgerliche Sache ist, wenn Sie versuchen, an einen undefinierten Wert zu binden. Stellen Sie sich im obigen Beispiel vor, dass das Datenobjekt nur {} nicht {value: 'some text'} ist. In diesem Fall werden Sie in Schwierigkeiten geraten, aber mit der folgenden Optimierung wird es Ihnen gut gehen:

<div data-bind="text: $data['value']"></div> 
Dreizack D'Gao
quelle
5

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

https://github.com/JonKragh/knockthrough

Es hebt Bindungsfehler hervor und gibt einen Speicherauszug des Datenkontexts 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

Geben Sie hier die Bildbeschreibung ein

Dank an RP Niemeyer für seine hervorragenden Knockout-Codebeispiele auf SO, die mich an diesen Punkt bringen.

Jon Kragh
quelle
3

Der einfachste Weg, um zu sehen, welche Daten an die Bindung übergeben werden, besteht darin, die Daten an die Konsole zu senden:

<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 löscht $ data in das Konsolenbrowserfenster.

Dmitry Pavlov
quelle
2

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 anhalten und elementund valueAccessor()wird wertvolle Informationen enthalten.

Aditya MP
quelle
Es ist keine benutzerdefinierte Bindung erforderlich. Werfen
Adam Wolski
1
Ja, ich stimme zu, dass es nicht unbedingt notwendig ist, dies so zu tun. Ich wollte nur darauf hinweisen, dass dies ein Debugging-Stil ist. Jeder scheint es zu mögen, es auf seine eigene Weise zu tun. :)
Aditya MP
1

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

Filip Cordas
quelle
Ich wette, es hat nichts mit Visual Studio oder IE zu tun.
Serhiy
@Serhiy Dasselbe gilt für Chrome, aber in Chrome. Ich denke, Sie könnten auf die Datei ohne Chrome zugreifen. Ich glaube nicht, dass Sie in VS auf die Datei zugreifen können.
Filip Cordas
0

Das funktioniert bei mir:

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