Застосування, поради та особливості
Навіщо потрібен Knockout.js?
- Мати можливість легко наповнювати інтерфейс даними з json-подібного об'єкта (моделі):
Відписувався від змін:
Що таке атрибут data-bind і bindings?
Knockout.js пропонує набір стандартних прив'язок (bindings), які дозволяють редагувати стилі, контент, обробники та інше, створюючи магічні речі. Крім того, можна писати свої прив'язки, про це чудово розказано знову ж в доках.
На цьому закінчимо опис того, навіщо ж потрібен нокаут, все інше ви самі знаєте на якому сайті знайти і перейдемо до деяким не очевидним новачкові речей.
Робота з observableArray
Припустимо, вам треба динамічно змінювати масив, на який підписані якісь обробники (або інтерфейс). Наприклад, ви отримали нову партію даних з сервера і в циклі додаєте їх в масив.
Якщо зробити все в лоб - то обробник зміни відпрацює стільки раз, скільки елементів ви додасте. І це позначиться на продуктивності. Приклад взятий з knockmeout.net
Так робити не треба:
Набагато краще так:
Knockout.js потрібен в проекті насамперед для наповнення інтерфейсу даними. Найпоширеніший сценарій для цього - отримання AJAX-запитом JSON-даних з сервера і рендеринг, тобто оновлення контенту без перезавантаження сторінки.
Для цього нам потрібні фрагменти сторінки, які ми зможемо підміняти в інтерфейсі і наповнювати даними - тобто нам потрібні шаблони для різних даних. Knockout.js вміє працювати з різними видами шаблонів (jQuery.tmpl, underscore, нативний) - зупинимося на останньому (хоча нам навіть дозволено написати свій).
Чи не нативні шаблонизатор не підтримують використання деяких прив'язок всередині нього (зокрема, дуже приємний with. Який змінює контекст моделі для шаблону).
Тому в деяких випадках хочеться використовувати нативний шаблонизатор від knockout. Для цього в опціях треба передати templateEngine: ko.nativeTemplateEngine.instance. Що цікаво (і не сказано в документації) - цей параметр можна передавати і в прив'язці template.
Для програмного рендеринга шаблонів використовується команда:
Цю команду зручно викликати, наприклад, в методі _create () при створенні jquery-віджетів, які використовують шаблони, і робиться це так:
Так само для виклику шаблону з іншого шаблону використовується стандартна прив'язка template:
templateName - ім'я шаблону, на практиці це id блоку, в якому знаходиться верстка з шаблоном:
При цьому движок шаблону не «успадковується" при виклику вкладених шаблонів - якщо ми викликаємо шаблон з шаблону, оброблюваного нативним шаблонізатором, то внутрішній шаблон (якщо не вказати шаблонизатор примусово) все одно використовує дефолтний шаблонизатор (наприклад, jQuery.tmpl, якщо такий був підключений в проекті).
Тому движок треба вказувати кожен раз. Але ця особливість дозволяє нам одночасно використовувати різні шаблонизатор для вкладених шаблонів.
Шаблони без кореневого елемента
Іноді не хочеться створювати зайвий контейнер для вмісту шаблону, щоб не вийшло, що в нього вкладено всього один елемент. У самому шаблоні при цьому елемент може бути необхідний через прив'язок або стилів.
В такому випадку підходить стандартний для нокауту варіант (віртуальні елементи):
Хоча в документації він і не описаний.
Налагодження в шаблонах
Найчастіша операція при програмуванні - налагодження (хоча деякі можуть посперечатися). Спосіб нижче дозволить вам виводити повідомлення в консоль використовуючи оператор кома і оператор угруповання (докладніше про ці оператори).
Зміна контексту за допомогою with і foreach - підводний камінь
Припустимо, що у нас є масив, в якому зберігаються рядки, які ми хочемо відстежувати.
Виглядає ініціалізація масиву приблизно так:
І ми хочемо вивести форму, що складається з input для її редагування якось ось так:
У такого запису текстові поля не працюватимуть у дві сторони - зміни тексту в полі не буде впливати на елементи масиву, але зміна елементів масиву буде впливати на вміст текстових полів. Приклад на jsfiddle.
Причина в тому, що шаблон вище по суті своїй еквівалентний наступному:
with: $ data - тут відбувається "розпакування" $ data: unwrapObservable ($ data) для того, щоб звернення виду $ data.somefield усередині шаблону працювали. Але ця розпакування підставляє замість $ data всередині - її значення. Як цю проблему обійти - навскидку не придумав.
висновок
За помилок в орфографії і пунктуації прошу в личку.