Skip to content

softmg/twoWayDBinJs

Repository files navigation

Двухсторонний биндинг в Vanilla JavaScript

Каждый, кто знает любой js framework (разрабатывал на нем) знает всю прелесть двустороннего биндинга. Давайте попробуем применить его в простом vanilla js. Для тех, кто до сих пор не знают об этом, двухсторонний датабиндинг означает, что когда вы что-либо меняете в модели, отображение (view) обновляется и при любом изменении в отображении, модель обновляется. Ну, а теперь давайте попробуем просто реализовать эту функцию в vanilla js. Давайте возьмем 4 текстовых поля, в которых легко продемонстрировать способ двухстороннего биндинга. Вот наш маленький кусочек html кода:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>2 Way Data Binding</title>
</head>
    <body>
        Name: <input class="name" type="text">
        <input class="name" type="text">
        <hr/>
        Age: <input class="age" type="text">
        <input class="age" type="text">
        <hr />
        <button onclick="log()">See $scope Values</button>
        <hr />
        <button onclick="changeNameByCode()">Set Name property to Hurry</button>
        <hr />
        <button onclick="changeAgeByCode()">Set Age property to 23</button>
        <script src="/dist/app.bundle.js"></script>
        <hr />
    </body>
</html>

Теперь давайте посмотрим на наш волшебный код JavaScript, который будет делать магию для нас:

class TwoWayDatabinding {
    static attachEvent (classNames) {
        classNames.forEach((className) => {
            const elementsByClass = Array.from(document.getElementsByClassName(className));

            addScopeToProperty(className);
            elementsByClass.forEach(elementToBind => elementToBind.onkeyup = function () {
                    $scope[className] = elementToBind.value;
                }
            )

            function addScopeToProperty(prop) {
                if (!$scope.hasOwnProperty(prop)) {
                    let value;
                    Object.defineProperty($scope, prop, {
                        set: (newValue) => {
                            elementsByClass.forEach(el => el.value = newValue);
                            value = newValue;
                            console.log('Set element with classname "%s" value "%s"', className, newValue);
                        },
                        get: () => value,
                        enumerable: true
                    });
                }
            }
        });
    };
}

Использовать класс TwoWayDatabinding мы можем так:

import TwoWayDatabinding from './twoWayDatabinding.js';

const bindClasses = ["name", "age"];
TwoWayDatabinding.attachEvent(bindClasses);

Вот подробное объяснение кода выше:

  • В массиве bindClasses находятся классы элементов, к которым мы должны применить двухсторонний биндинг.
  • В функции attachEvent мы проходимся по массиву классов и для каждого извлекаем все элементы по названию класса document.getElementsByClassName(className).
  • На каждый класс мы добавляем в объект $scope setter для соответствующего поля.
  • Для каждого найденного элемента на событие onkeyup изменяется соответсвующее поле в объекте $scope.

Объяснение функции addScopeToProperty:

  • Проверяем есть ли в $scope заданное поле
  • Объявляем переменную “value” которая может измениться в callback сеттера.
  • Затем в функции “Object.defineProperty” устанавливается callback сеттера в которой устанавливается новое значение переменной value и устанавливает значение всех элементов с заданным классом.
  • В геттере возвращается значение переменной value.
  • Для разрешение итерации по полям $scope устанавливаем значение enumerable в true.

Deployment:

  • npm i
  • npm run start:dev
  • Перейти по адресу http://localhost:8080 (порт может отличаться)

Ссылка на jsfiddle

About

2 Way Data Binding in Vanilla JS

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published