Динамическое связывание данных в HTML и JS
Всем доброго времени суток.
Если вы задаетесь одним из следующих вопросов:
- что такое динамическое связывание данных?
- как работает связывание данных в AngularJS или ему подобных MVVM-фреймворках?
- чем, черт возьми, MPV отличается от MVVM?
Тогда вам под кат…
И да… в конце, как всегда, ссылка на код ;)
Про MVP:
MVP (Model-View-Presenter) — это один из самых распространенных шаблонов проектирования UI.
Суть его заключается в следующем:
- Presenter подписывается на события от View
- View эмитит события
- Presenter ловит события и делает запросы в Model
- При получении ответа от Model, Presenter обновляет View
Сразу же в глаза бросается ключевое отличие MVP от MVC: MVP, в отличии от MVC, имеет двустороннюю связь с View.
Запомним и пойдем дальше…
Про MVVM:
MVVM (Model-View-ViewModel) — это улучшеная форма MVP, при чем грань между ними так тонка, что иногда думаешь: «О, небо! За что ты так со мной?»
Сейчас объясню что я имею ввиду.
Суть MVVM заключается в следующем:
- ModelView подписывается на события от View
- View эмитит события
- ModelView ловит события и делает запросы в Model
- При получении ответа от Model, ModelView обновляет View
Если отбросить формальности, то так оно и есть. Поэтому я и сказал, что грань между MVP и MVVM очень тонка.
Глобально, разница лишь в том, что MVVM реализует более гибкий слушатель событий от View.
При чем реализует таким образом, что становится доступным так называемое декларативное динамическое связывание данных.
Про динамическое связывание данных:
Это такой механизм, при котором, изменив значение модели с любой стороны (со стороны View или Model), это изменение моментально вступит в силу. То есть, изменив значение в Model (в MVVM — ViewModel частично берет на себя функцию модели), оно сразу отобразится во View и наоборот.
Вы можете спросить: «Если в MVP есть двусторонняя связь между View и Presenter, то почему мы не можем реализовать динамическое связывание данных на MVP?».
Ответ очень прост — можем!
По сути, MVP уже подразумевает динамическое связывание данных в той или иной степени.
И, если MVP это чисто императивный подход к связыванию данных, то MVVM — декларативный.
Вот и вся разница.
Но суть у них одна и та же!
Про реализацию:
Теперь рассмотрим вопросы, связанные с реализаций динамического связывания данных.
Начнем с того, что, на текущий момент, браузер не способен динамически отслеживать изменение значений в переменных.
Конечно, есть такая штука как Object.observe (), но эта вещь, пока еще, не является частью стандарта.
Поэтому исходим из того, что
браузер не способен динамически отслеживать изменение значений в переменных
Соответсвенно, необходимо как-то понимать: когда нужно произвести синхронизацию между Model и View.
В современных фреймворках, типа Angular или Knockout, к этому вопросу подходят очень просто: вешают слушатели на разные события от элемента, которому необходимо динамическое связывание данных.
Например, для text input вешается слушатель на событие keyup.
Для button — click
И т.д.
Внутри обработчика происходит чтение новых данных и затем запускается механизм синхронизации оных с Model.
Вот, собственно, и вся история.
Кстати, если вы используете Angular, то, скорее всего, вам очень часто приходится прибегать к использованию таких вещей, как сервис $timeout…
Если вы используете $timeout на автоматизме, потому что так написано где-то на stack overflow, но не понимаете его сути, то знайте, что $timeout ждет, пока закончится текущий $digest-цикл, затем выполняет код, который вы ему передали, и затем снова запускает $digest-цикл. Именно так и достигается обновление данных, если оно было инициировано не из внутренностей Angular.
Что такое $digest-цикл?
В AngularJS это как раз и есть процесс синхронизации значений между Model и View.
И, как обещал, ссылка на Gist, в котором реализовано простейшее динамическое связывание данных.
В нескольких словах:
- выбираем все элементы, у которых есть атрибут data-bind
- регистрируем эти элементы как слушатели изменений модели
- вешаем на document общий обработчик, который будет производить синхронизацию между View и Model
Спасибо за внимание.