Как отладить ошибки привязки шаблона для KnockoutJS?

199

У меня постоянно возникают проблемы с отладкой в ​​шаблонах KnockoutJS.

Скажем, я хочу привязать к свойству под названием " items", но в шаблоне я делаю опечатку и привязываю к (несуществующему) свойству " item".

Использование отладчика Chrome только говорит мне:

"item" is not defined.

Существуют ли инструменты, методы или стили кодирования, которые помогают мне получить больше информации о проблеме связывания?

RogierBessem
источник

Ответы:

344

Одна вещь, которую я делаю довольно часто, когда возникает проблема с тем, какие данные доступны в определенной области, - это заменить шаблон / раздел чем-то вроде:

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

Или, если вы хотите немного более читаемую версию:

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

Это будет выплевывать данные, которые связаны в этой области и позволит вам убедиться, что вы вкладываете вещи соответствующим образом.

Обновление: начиная с KO 2.1 , вы можете упростить его до:

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

Теперь аргументы переданы JSON.stringify.

Р.П. Нимейер
источник
ооо. Мне тоже нужно задать этот вопрос. Использовал сложный кусок кода для данных console.log. Теперь это намного проще.
AlfeG
3
Я должен больше думать о подсказках отладки и возможно сделать сообщение в блоге. Еще один, который приходит на ум, - это делать ручные подписки на наблюдаемые или вычисляемые наблюдаемые, чтобы наблюдать изменение значений. Например, если nameможно наблюдатьname.subscribe(function(newValue) { console.log("name", newValue); });
Р.П. Нимейер
1
Возможно, потому что этот ответ относительно старый, но почему бы не использовать console.log и использовать всю мощь отладчика для просмотра свойств объекта? См., Например: stackoverflow.com/a/16242988/647845
Дирк Бур
1
@DirkBoer - использование console.log также может быть отличным способом. Часто я хочу видеть данные рядом с моими элементами, как в foreachсценарии, и мне легче видеть их на странице в соответствующей визуализированной разметке, чем просеивать через консоль. Просто зависит от ситуации. Еще несколько моих мыслей здесь: knockmeout.net/2013/06/… . Кроме того, вы можете записать «чистую» версию в вашей привязке, как console.log(ko.toJS(valueAccessor()).
РП Нимейер
1
@RuneJeppesen - я не уверен, какие данные вы сериализуете, но что-то вроде этого может помочь: knockmeout.net/2011/04/…
Р.П. Нимейер,
61

Если вы используете Chrome для разработки, есть действительно отличное расширение (с которым я не связан), называемое Knockoutjs context debugger, которое показывает вам контекст привязки непосредственно на панели элементов Developer Tools.

neverfox
источник
3
Я бы хотел, чтобы Firefox или Firebug имели это. Кто-нибудь знает о такой вещи?
Патрик Салапски
Оказывается, поддержка была прекращена. Вызывает сбой chrome, если вы используете сложную структуру привязки данных. Не работал ни для одного из моих проектов в течение примерно года.
Арктика
Жаль это слышать, хотя я давно перешел из нокаутом в Эмбер.
neverfox
1
Это работает (в основном) хорошо для меня, и у меня есть некоторые действительно сложные структуры. Я не пробовал его, но в разделе «Опции» для расширения предлагается: «Если у вас возникли сбои, возможно, у вас не сериализуемая модель представления. Вы можете отключить сериализацию». Под сообщением есть флажок для отключения этой функции.
Гринн
очень полезно мгновенно, ты.
Андрей
37

Определите bindingHandler один раз , где-нибудь в ваших файлах библиотеки JavaScript.

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

чем просто использовать это нравится это:

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

преимущества

  • Используйте всю мощь отладчика Chrome, например, « Показать на панели элементов».
  • Вам не нужно добавлять пользовательские элементы в DOM, просто для отладки

введите описание изображения здесь

Дирк Бур
источник
32

Я нашел другой, который может быть полезным. Я отлаживал некоторые привязки и пытался использовать пример Райана. Я получил ошибку, что JSON обнаружил круговой цикл.

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

Но, используя этот подход, заменили значение привязки данных следующим:

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

Теперь, если я нажимаю на элемент PRE, когда открыто окно отладки Chrome, я получаю хорошо заполненное окно переменных области видимости.

Нашел немного лучший способ для этого:

<pre data-bind="text: ko.computed(function() { debugger; })"></pre>
RogierBessem
источник
Действительно полезно. Возникли проблемы с нокаутирующими круговыми циклами и разметкой Razor с использованием <pre data-bind = "text: ko.toJSON ($ data, null, 2)"> </ pre>. <Pre ... debugger> - идеальный обходной путь. По какой-то причине входные данные RAZOR, такие как @ Html.CheckBox, ломали ko.toJSON.
Арктика
20

Пошаговое руководство

  1. Для этого руководства мы будем использовать один из официальных примеров KnockoutJS .
  2. Скажем, вы хотите увидеть данные за вторым контактом (сэнсэй Мияги).
  3. Щелкните правой кнопкой мыши первое поле ввода второго контакта (с текстом «Сенсей»).
  4. Выберите «Проверить элемент». Откроется панель инструментов разработчика Chrome.
  5. Откройте окно консоли JavaScript. Вы можете получить доступ к консоли, щелкнув >=значок в нижнем левом углу панели инструментов разработчика Chrome, или открыв вкладку «Консоль» на панели инструментов разработчика Chrome, или нажав Ctrl+ Shift+J
  6. Введите следующую команду и нажмите Enter: ko.dataFor($0)
  7. Теперь вы должны увидеть данные, привязанные ко второй строке. Вы можете расширить данные, нажав маленький треугольник слева от объекта, чтобы перемещаться по дереву объектов.
  8. Введите следующую команду и нажмите Enter: ko.contextFor($0)
  9. Теперь вы должны увидеть сложный объект, который содержит весь контекст Knockout, включая корень и всех родителей. Это полезно, когда вы пишете сложные выражения связывания и хотите поэкспериментировать с различными конструкциями.

Пример вывода при следовании приведенному выше руководству

Что это за черная магия?

Этот трюк представляет собой сочетание функции $ 0-4 $ в Chrome и служебных методов KnockoutJS . Короче говоря, Chrome запоминает , какие элементы вы выбрали в Chrome Developer Toolbar и выставляет эти элементы под псевдонимом $0, $1, $2, $3, $4. Поэтому, когда вы щелкаете правой кнопкой мыши по элементу в вашем браузере и выбираете «Проверить элемент», этот элемент автоматически становится доступным под псевдонимом $0. Вы можете использовать этот трюк с KnockoutJS, AngularJS, jQuery или любым другим фреймворком JavaScript.

Другая сторона хитрости - это служебные методы KnockoutJS ko.dataFor и ko.contextFor:

  • ko.dataFor(element) - возвращает данные, которые были доступны для привязки к элементу
  • ko.contextFor(element) - возвращает весь контекст привязки, который был доступен элементу DOM.

Помните, JavaScript-консоль Chrome - это полнофункциональная среда выполнения JavaScript. Это означает, что вы не ограничены только просмотром переменных. Вы можете сохранить выходные данные ko.contextForи манипулировать моделью представления непосредственно из консоли. Попробуй var root = ko.contextFor($0).$root; root.addContact();и посмотри, что получится :-)

Удачной отладки!

Мартин Девиллерс
источник
7

Проверьте действительно простую вещь, которую я использую:

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

Или

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

Тогда в HTML, скажем, у вас было:

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

Просто замените его на

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

Более продвинутый:

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

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

Наслаждаться :)

ОБНОВИТЬ

Еще одна неприятная вещь, когда вы пытаетесь связать с неопределенным значением. Представьте, что в приведенном выше примере объект данных просто {}, а не {value: 'some text'}. В этом случае у вас будут проблемы, но со следующей настройкой у вас все будет хорошо:

<div data-bind="text: $data['value']"></div> 
Трезубец д'Гао
источник
5

Я создал проект github под названием knockthrough.js, чтобы помочь визуализировать эти ошибки.

https://github.com/JonKragh/knockthrough

Он выделяет ошибки привязки и дает дамп текстового контекста на этом узле.

Вы можете поиграть с образцом здесь: http://htmlpreview.github.io/?https://github.com/JonKragh/knockthrough/blob/master/default.htm

введите описание изображения здесь

Благодарю Р.П. Нимейера за его превосходные примеры кода Knockout на SO, чтобы донести до меня этот момент.

Джон Краг
источник
3

Самый простой способ увидеть, какие данные передаются в привязку, - это сбросить данные в консоль:

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

Knockout оценивает значение для привязки текста ( здесь можно использовать любую привязку ) и сбрасывает $ data на панель браузера консоли.

Дмитрий Павлов
источник
2

Все остальные ответы будут работать отлично, я просто добавляю, что мне нравится делать:

По вашему мнению (если вы уже связали ViewModel):

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

Код нокаута:

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

Это приостановит код в отладчике elementи valueAccessor()будет содержать ценную информацию.

Адитья М.П.
источник
Там нет необходимости для пользовательского связывания. Взгляните на stackoverflow.com/documentation/knockout.js/5066/…
Адам Вольски,
1
Да, я согласен, что нет определенной необходимости делать это таким образом, я просто хотел отметить, что это один стиль отладки ... Кажется, всем нравится делать это по-своему :)
член парламента Адитья,
1

Если вы разрабатываете в Visual studio и IE, мне это нравится больше, data-bind="somebinding:(function(){debugger; return bindvalue; })()"мне нравится больше, чем функция echo, так как он будет идти к сценарию со всеми привязками, а не к файлу eval, и вы можете просто посмотреть на $ context $ data (я использую это и в Chrome);

Филип Кордас
источник
Бьюсь об заклад, это не имеет ничего общего с Visual Studio или IE.
Сергей
@Serhiy То же самое с Chrome, но в Chrome, я думаю, вы можете получить доступ к файлу без него, я не думаю, что вы можете получить доступ к файлу в VS.
Филип Кордас
0

Это работает для меня:

<div data-bind="text: function(){ debugger; }()"></div>
Роберт Дж
источник