BOToD

Code Sandbox
GitHub 🇷🇺
|||

Общее

Введение

 BOToD — Библиотека для двустороннего реактивного связывания JavaScript данных с DOM элементами. Для отслеживания Object он лениво-рекурсивно оборачивается в Proxy. Это значит, что вложенные Object'ы и массивы будут заменены на свои Proxy только при необходимости. Вся реализация происходит в коде, нет никаких биндингов в HTML.

Быстрый старт

Подключаем библиотеку
Сейчас, и наверное далее, будет использоваться только CDN для подключения библиотеки
<script src="https://cdn.jsdelivr.net/gh/Graff46/BOToD@latest/src/BOToD.js"></script>
Создаем экземпляр приложения:
const myApp = App();
Создаем прокси объекта с данными:
const obj = {
    key: {
        k1: {
            l1: {m1: 1, m11: 2,}
        }, 
    },

    one: {
        k2: {
            l2: {m2: 22,}
        }
    },

    two: 5,
};
const myApp = App();
const appData = myApp.buildData(obj);
Создадим привязку поля объекта с текстовым элементом.
Аргументы:
myApp.bind('.txt-input', x => appData.key.k1.l1.m1);
Создадим input элементы по количеству элементов в массиве (объекте) и каждому новому элементу будет установлен атрибут value
Аргументы:
myApp.repeat('div.input-block > input', x => appData.k1.l1, k => appData.k1.l1[k]);

Основы

Создание экземпляра приложения

После того, как библиотека будет подключена в глобальной области видимости появится функция App, которая возвращает экземпляр приложения.
Следите за тем, чтобы не переназначить идентификатор App в глобальной области видимости
const myApp = App();
const myApp = App(App.eventTypeInput | App.textContent);
const myApp2 = App(App.eventTypeInput + App.textContent);
При создании экземпляра приложения можно задать настройки определяющие правила работы данного экземпляра приложения. Указание настроек осуществляется путём указания флагов в аргументах функции App указанной выше. Идентификаторы флагов доступны как статические свойства объекта функции App. На данный момент доступны следующие флаги: Флаги являются битовыми флагами, их можно сочетать с помощью операции битового оператора "ИЛИ" или арифметического сложения

Создание отслеживаемого объекта

Для обеспечения реактивности библиотека использует Proxy. Поэтому, чтобы отслеживать изменения в объекте, необходимо его обернуть в Proxy. Для этого используется метод экземпляра приложения: buildData
const data = {key: {k1: {l1: {m1: 1, m11: 2}}}};
const myApp = App();

const appData = myApp.buildData(data);

Связывания

bind

Простое двустороннее связывание. Отслеживает изменение поля объекта (массива) и меняет свойство value или textContent DOM элемента. Если поменять значение в DOM элементе - то изменится связанное поле объекта соответственно.
Аргументы:
const myApp = App();
const appData = myApp.buildData({key: {k1: {l1: {m1: 1, m11: 2}}}});

myApp.bind('.txt-input', () => appData.key.k1.l1.m1);
Возможен такой вариант:
const myApp = App();
const appData = myApp.buildData({key: {l1: {m1: 1, m11: 2}}});
const obj = appData.key.l1;
const elm = document.querySelector('.txt-area');

myApp.bind(elm, () => obj.m1);

xrBind

Расширенное двустороннее связывание. Принцип действия аналогичен bind.
Аргументы: Реализация метода bind методом xrBind:
const myApp = App();
const appData = myApp.buildData({key: {m1: 1, m11: 2}});

myApp.xrBind('.txt-area', () => appData.m1, el => el.value = appData.m1, (el, val) => el.value = val);

repeat

Метод копирования DOM объекта по количеству элементов итерируемого объекта, также устанавливает привязки.
Аргументы для реализации с тремя аргументами:
const myApp = App();
const appData = myApp.buildData({key: {m1: 1, m11: 2}});

myApp.repeat('.list-input', x => appData.key, k => appData.key[k]);
Аргументы для реализации с четырьмя аргументами (аналогично xrBind):
const myApp = App();
const appData = myApp.buildData({key: {m1: 1, m11: 2}});

myApp.repeat('.i2', x => appData.m1, (el, k) => el.value = appData.key[k], (el, k) => appData.key[k] = el.value);
Есть варианты использовать данный метод для создания элементов без привязок и реактивности:

Развязывания

unbind

Удаление и перезапись полей объекта не приводит к удалению связываний с этими полями! Данный метод используется для снятия связываний с JS объекта или DOM элемента.
Аргументы:
const myApp = App();
const appData = myApp.buildData({key: {m1: 1, m11: 2}});

myApp.repeat('.i2', x => appData.key, (el, k) => el.value = appData.key[k], (el, k) => appData.key[k] = el.value);
myApp.bind('input#cd', () => appData.key.m11);

myApp.unbind('input#cd'); // unbind from an DOM element
myApp.unbind(appData.key); // unbind from an JS Object

Важные заметки

Не используйте аргументы в методах и функциях всверх тех, что указаны в данном руководстве!

В методах xrBind и repeat с 4 аргументами: в аргументе-функции в которой указываем привязку DOM элемента к JS данным (3-й аргумент) нужно в коде читать поле JS объекта, чтобы сработал перехват Proxy и связал нужное поле JS объекта. Этого можно не делать, тогда будет отсутствовать привязка JS данных с DOM объектом.

Можно использовать все методы для заполнения данными DOM элементов без каких либо привязок и реактивности, достаточно использовать в качестве источника данных неотслеживаемый JS объект (не использовать App.buildData)

Если удалить дочерний JS объект оператором delete, то отвязки биндингов не будет.
const myApp = App();
const appData = myApp.buildData({key: {m1: 1, m11: 2}});

myApp.bind('input#cd', () => appData.key.m11);

setTimeout(() => delete appData.key.m11, 2000);
setTimeout(() => appData.key = {m11: 55}, 2000)
В вышепоказанном коде через 2 секунды значение DOM элемента будет сброшено, а еще через 2 секунды значение DOM элемента будет 55.