Jak debugować błędy wiązania szablonu dla KnockoutJS?

199

Wciąż mam problemy z debugowaniem problemów w szablonach KnockoutJS.

Powiedz, że chcę powiązać z właściwością o nazwie „ items”, ale w szablonie robię literówkę i wiążę się z (nieistniejącą) właściwością „ item”.

Korzystanie z debugera Chrome mówi mi tylko:

"item" is not defined.

Czy istnieją narzędzia, techniki lub style kodowania, które pomagają mi uzyskać więcej informacji na temat problemu z wiązaniem?

RogierBessem
źródło

Odpowiedzi:

344

Jedną z rzeczy, które robię dość często, gdy występuje problem z tym, jakie dane są dostępne w pewnym zakresie, jest zastąpienie szablonu / sekcji czymś takim jak:

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

Lub, jeśli chcesz nieco bardziej czytelną wersję:

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

Spowoduje to wyplenienie danych powiązanych w tym zakresie i pozwoli upewnić się, że odpowiednio zagnieżdżasz rzeczy.

Aktualizacja: od KO 2.1 możesz uprościć to do:

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

Teraz argumenty są przekazywane do JSON.stringify.

RP Niemeyer
źródło
och Też muszę zadać to pytanie. Użyłem skomplikowanego fragmentu kodu do danych console.log. Teraz jest o wiele łatwiej.
AlfeG
3
Muszę więcej pomyśleć o poradach dotyczących debugowania i być może opublikować post na blogu. Innym, który przychodzi na myśl, jest ręczne dokonywanie subskrypcji obserwowalnych lub obliczalnych obserwowalnych w celu obserwowania zmian wartości. Jakby namemożna zaobserwowaćname.subscribe(function(newValue) { console.log("name", newValue); });
RP Niemeyer
1
Może dlatego, że ta odpowiedź jest stosunkowo stara, ale dlaczego nie skorzystać z console.log i wykorzystać pełną moc debugera do przeglądania właściwości obiektu? Patrz np .: stackoverflow.com/a/16242988/647845
Dirk Boer
1
@DirkBoer - używanie konsoli.log może być również świetnym sposobem. Często jednak chcę widzieć dane obok moich elementów, jak w foreachscenariuszu, i łatwiej mi jest zobaczyć na stronie w obrębie odpowiedniego renderowanego znacznika niż przesuwać przez konsolę. Tylko zależy od sytuacji. Więcej moich przemyśleń tutaj: knockmeout.net/2013/06/… . Możesz również chcieć zalogować „czystą” wersję w swoim powiązaniu jak console.log(ko.toJS(valueAccessor()).
RP Niemeyer
1
@RuneJeppesen - Nie jestem pewien, jakie dane szeregujesz, ale coś takiego może pomóc: knockmeout.net/2011/04/…
RP Niemeyer
61

Jeśli używasz Chrome do programowania, istnieje naprawdę świetne rozszerzenie (z którym nie jestem powiązany) o nazwie Debugger kontekstowy Knockoutjs, który pokazuje kontekst wiązania bezpośrednio w panelu Elementy narzędzi programistycznych.

neverfox
źródło
3
Chciałbym, żeby Firefox lub Firebug miał to. Ktoś wie o takiej rzeczy?
Patrick Szalapski
Wygląda na to, że wsparcie zostało porzucone. Powoduje awarię chrome, jeśli używasz złożonej struktury powiązania danych. Od około roku nie pracuje dla żadnego z moich projektów.
Arktyczny
Przykro mi to słyszeć, choć już dawno przeniosłem się z KO do Embera.
neverfox
1
Działa (głównie) dobrze dla mnie i mam kilka naprawdę skomplikowanych struktur. Nie próbowałem tego, ale w Opcjach rozszerzenia sugeruje: „Jeśli wystąpią awarie, prawdopodobnie masz niemożliwy do serializacji model widoku. Możesz wyłączyć serializację”. Pod komunikatem znajduje się pole wyboru umożliwiające wyłączenie tej funkcji.
Grinn,
niezwykle przydatne natychmiast, ty.
Andrew
37

Zdefiniuj obiekt bindingHandler raz , gdzieś w plikach biblioteki JavaScript.

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

niż zwykłe użycie lubi to:

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

Zalety

  • Wykorzystaj pełną moc debugera Chrome, np Ujawnij w panelu elementów
  • Nie musisz dodawać niestandardowych elementów do DOM, tylko w celu debugowania

wprowadź opis zdjęcia tutaj

Dirk Boer
źródło
32

Znalazłem inny, który może być pomocny. Debugowałem niektóre powiązania i próbowałem na przykładzie Ryans. Wystąpił błąd polegający na tym, że JSON znalazł okrągłą pętlę.

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

Ale stosując to podejście zastąpiono wartość wiązania danych następującą:

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

Teraz, jeśli kliknę element PRE, mając otwarte okno debugowania chrome, otrzymam ładnie wypełnione okno zmiennych zakresu.

Znalazłem trochę lepszy sposób:

<pre data-bind="text: ko.computed(function() { debugger; })"></pre>
RogierBessem
źródło
Naprawdę użyteczne. Wystąpiły problemy z nokautowymi okrągłymi pętlami i problemy ze znacznikami Razor przy użyciu <pre data-bind = "text: ko.toJSON ($ data, null, 2)"> </pre>. <Pre ... debugger> to idealne obejście. Z jakiegoś powodu dane wejściowe RAZOR, takie jak @ Html.CheckBox, łamały ko.toJSON.
Arctic
20

Przewodnik krok po kroku

  1. W tym przewodniku wykorzystamy jeden z oficjalnych przykładów KnockoutJS .
  2. Powiedz, że chcesz zobaczyć dane za drugim kontaktem (Sensei Miyagi).
  3. Kliknij prawym przyciskiem myszy pierwsze pole wprowadzania drugiego kontaktu (ten z tekstem „Sensei”).
  4. Wybierz „Sprawdź element”. Otworzy się pasek narzędzi Chrome dla programistów.
  5. Otwórz okno konsoli JavaScript. Aby uzyskać dostęp do konsoli, kliknij >=ikonę w lewym dolnym rogu paska narzędzi dla programistów Chrome lub otwierając kartę „Konsola” na pasku narzędzi dla programistów Chrome lub naciskając Ctrl+Shift +J
  6. Wpisz następujące polecenie i naciśnij klawisz Enter: ko.dataFor($0)
  7. Powinieneś teraz zobaczyć dane powiązane z drugim rzędem. Możesz rozwinąć dane, naciskając mały trójkąt po lewej stronie obiektu, aby poruszać się po drzewie obiektów.
  8. Wpisz następujące polecenie i naciśnij klawisz Enter: ko.contextFor($0)
  9. Powinieneś teraz zobaczyć złożony obiekt, który zawiera cały kontekst Knockout, w tym root i wszystkich rodziców. Jest to przydatne, gdy piszesz złożone wyrażenia wiążące i chcesz eksperymentować z różnymi konstrukcjami.

Przykładowe dane wyjściowe po zastosowaniu powyższego przewodnika

Czym jest ta czarna magia?

Ta sztuczka jest połączeniem funkcji Chrome 0–4 USD i metod użyteczności KnockoutJS . W skrócie, Chrome zapamiętuje, które elementy zostały wybrane w Chrome Developer Toolbar i eksponuje te elementy pod pseudonimem $0, $1, $2, $3, $4. Więc kiedy klikniesz prawym przyciskiem myszy element w przeglądarce i wybierzesz „Sprawdź element”, ten element automatycznie stanie się dostępny pod aliasem$0 . Możesz użyć tej sztuczki w KnockoutJS, AngularJS, jQuery lub w dowolnym innym języku JavaScript.

Drugą stroną sztuczki są metody narzędziowe KnockoutJS ko.dataFor i ko.contextFor:

  • ko.dataFor(element) - zwraca dane, które były dostępne do powiązania z elementem
  • ko.contextFor(element) - zwraca cały kontekst wiązania, który był dostępny dla elementu DOM.

Pamiętaj, że konsola JavaScript Chrome to w pełni funkcjonalne środowisko wykonawcze JavaScript. Oznacza to, że nie jesteś ograniczony tylko do patrzenia na zmienne. Możesz przechowywać dane wyjściowe ko.contextFori manipulować viewmodelem bezpośrednio z konsoli. Spróbuj var root = ko.contextFor($0).$root; root.addContact();i zobacz, co się stanie :-)

Miłego debugowania!

Martin Devillers
źródło
7

Sprawdź naprawdę prostą rzecz, której używam:

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

Lub

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

Powiedzmy, że w html:

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

Po prostu zamień na

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

Bardziej zaawansowany:

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

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

Cieszyć się :)

AKTUALIZACJA

Inną irytującą rzeczą jest próba powiązania z nieokreśloną wartością. Wyobraź sobie w powyższym przykładzie, że obiekt danych to po prostu {} nie {wartość: „jakiś tekst”}. W takim przypadku będziesz mieć kłopoty, ale z następującymi poprawkami będziesz w porządku:

<div data-bind="text: $data['value']"></div> 
Trident D'Gao
źródło
3

Najłatwiejszym sposobem sprawdzenia, jakie dane są przekazywane do wiązania, jest upuszczenie danych na konsolę:

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

Knockout oceni wartość wiązania tekstowego ( w rzeczywistości można tu użyć dowolnego powiązania ) i opróżni $ dane do panelu przeglądarki konsoli.

Dmitrij Pawłow
źródło
2

Wszystkie pozostałe odpowiedzi będą działać świetnie, dodam tylko to, co lubię:

W twoim widoku (zakładając, że już związałeś ViewModel):

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

Kod nokaut:

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

Spowoduje to wstrzymanie kodu w debuggerze elementi valueAccessor()będzie zawierać cenne informacje.

Aditya MP
źródło
nie ma potrzeby niestandardowego wiązania. Spójrz na stackoverflow.com/documentation/knockout.js/5066/...
Adam Wolski
1
Tak, zgadzam się, że nie ma takiej potrzeby, chciałem tylko zaznaczyć, że jest to jeden styl debugowania ... wydaje się, że wszyscy lubią robić to po swojemu :)
poseł Aditya
1

Jeśli rozwijasz się w Visual Studio i IE podoba mi się to bardziej data-bind="somebinding:(function(){debugger; return bindvalue; })()", bardziej podoba mi się to niż funkcja echa, ponieważ przejdzie ona do skryptu ze wszystkimi powiązaniami, a nie do pliku eval i możesz po prostu spojrzeć na dane $ kontekst $ (używam to także w Chrome);

Filip Cordas
źródło
Założę się, że nie ma to nic wspólnego z Visual Studio lub IE.
Serhiy
@Serhiy To samo z chrome, ale w chrome Myślę, że możesz uzyskać dostęp do pliku bez niego Nie sądzę, że możesz uzyskać dostęp do pliku w VS.
Filip Cordas,
0

To działa dla mnie:

<div data-bind="text: function(){ debugger; }()"></div>
Robert J.
źródło