Data binding for Backbone.js



Data binding for Backbone.js

0 0


Data-binding-for-Backbone.js


On Github tsareg / Data-binding-for-Backbone.js

Data binding for Backbone.js

Обзор существующих решений

Автор Константин Цареградский

Backbone.js - мощный фреймворк, но...

очень часто приходиться решать простейшие задачи не самым простым образом.

Задача

Есть форма редактирования имени и фамилии пользователя, из них генерируется полное имя.

 

First Name:

Last Name:

Full Name:

Set 'firstName' and 'lastName' to model

Vanilla Backbone.js

First Name:

Last Name:

Full Name: <%- firstName %> <%- lastName %>

var FullNameView = Backbone.View.extend({
    template: _.template($("script[type='text/template']").html()),
    events: {
        "change #firstName": "updateFirstName",
        "change #lastName": "updateLastName"
    },
    initialize: function () {
        this.listenTo(this.model, "change:firstName change:lastName", this.render);
    },
    render: function () {
        this.$el.html(this.template(model.toJSON()));
        return this;
    },
    updateFirstName: function () {
        this.model.set("firstName", this.$("#firstName").val());
    },
    updateLastName: function () {
        this.model.set("lastName", this.$("#lastName").val());
    }
});

var model = new Backbone.Model({firstName: "Luke", lastName: "Skywalker"}),
    view = new FullNameView({model: model, el: $("#container")});

view.render();

Vanilla Backbone.js

+ -
  • Много кода для такой простой задачи
  • Ре-рендеринг всей вьюхи каждый раз
  • В перспективе - причина создания собственного велосипеда

Есть решение проще!

Data Binding

Data Binding

Процесс связывания пользовательского интерфейса приложения с бизнес-логикой.

Эта концепция активно используется в таких популярных фреймворках как AngularJS, KnockoutJS и многих других.

KnockoutJS

First Name:

Last Name:

Full Name:

var ViewModel = function(first, last) {
    this.firstName = ko.observable(first);
    this.lastName = ko.observable(last);
};

ko.applyBindings(new ViewModel("Luke", "Skywalker"));

AngularJS

First Name:

Last Name:

Full Name: {{firstName}} {{lastName}}

function ctrlName($scope) {
    $scope.firstName = "Luke";
    $scope.lastName = "Skywalker";
}

К сожалению, из коробки Backbone не предоставляет такой функциональности. Однако существует множество сторонних решений:

Backbone.ModelBinding

First Name:

Last Name:

Full Name:

var ModelBindingView = Backbone.View.extend({
    template: $("script[type='text/template']").html(),

    render: function() {
        this.$el.html(this.template);
        Backbone.ModelBinding.bind(this);
        return this;
    }
});

var model = new Backbone.Model({ firstName: "Luke", lastName: "Skywalker" }),
    view = new ModelBindingView({ model: model, el: $("#container") });

view.render();

Backbone.ModelBinding

+ -
  • По сути, первый data binding для Backbone. Интересен для истории.
  • Ограниченое число binding'ов
  • Разработка остановлена
  • Новые версии Backbone официально не поддерживаются

Backbone.ModelBinder

First Name:

Last Name:

Full Name:

var ModelBinderView = Backbone.View.extend({
    template: $("script[type='text/template']").html(),

    initialize: function() {
        this.modelBinder = new Backbone.ModelBinder();
    },

    render: function() {
        this.$el.html(this.template);
        this.modelBinder.bind(this.model, this.el);
        return this;
    }
});

var model = new Backbone.Model({ firstName: "Luke", lastName: "Skywalker" }),
    view = new ModelBinderView({ model: model, el: $("#container") });

view.render();

Backbone.ModelBinder

+ -
  • Гибкость в настройке
  • Есть возможность привязаться к любому аттрибуту DOM элемента
  • Поддержка конвертеров и форматтеров
  • Поддержка коллекций с помощью Backbone.CollectionBinder
  • Сложный в освоении из-за большого количества настроек и параметров
  • Проект не активен, minor версия 1.0.6 от 5 ноября 2014, до этого коммиты были только в 2013

Backbone.DataBinding

First Name:

Last Name:

Full Name:

var DataBindingView = Backbone.View.extend({
    template: $("script[type='text/template']").html(),

    render: function() {
        this.$el.html(this.template);
        return this;
    }
});

var model = new Backbone.Model({ firstName: "Luke", lastName: "Skywalker" }),
    view = new DataBindingView({ model: model, el: $("#container") }),
    modelBinder = new Backbone.ModelBinder(view, model);

modelBinder.watch('value: firstName', { selector: '[name="firstName"]' });
modelBinder.watch('text: firstName', { selector: '#firstName' });
modelBinder.watch('value: lastName', { selector: '[name="lastName"]' });
modelBinder.watch('text: lastName', { selector: '#lastName' });

view.render();

Backbone.DataBinding

+ -
  • Есть возможность связать модель и представление извне, не трогая оригинальный код
  • Поддержка коллекций
  • Автор из Украины
  • Отсутсвтие какого-либо community - 2 контрибьютора, 0 форков
  • Много ручной работы
  • Последний коммит - год назад

Backbone.Stickit

First Name:

Last Name:

Full Name:

var StickitView = Backbone.View.extend({
    template: $("script[type='text/template']").html(),
    bindings: {
        '[name=firstName]': 'firstName',
        '[name=lastName]': 'lastName',
        '#fullName': {
            observe: ['firstName', 'lastName'],
            onGet: function(values) { return values[0] + ' ' + values[1]; }
        }
    },
    render: function() {
        this.$el.html(this.template);
        this.stickit();
        return this;
    }
});

var model = new Backbone.Model({ firstName: "Luke", lastName: "Skywalker" }),
    view = new StickitView({ model: model, el: $("#container") });

view.render();

Backbone.Stickit

+ -
  • Активно развивается, последний коммит - в начале ноября 2014
  • Большое community, серьезный автор - NY Times
  • Поддержка contenteditable DOM элементов
  • Computed свойства
  • Огромное количество настроек
  • Возможность форматирования и конвертирования
  • Data binding описывается в JavaScript коде, нет привязки к темплейтам
  • Доволен сложен в освоении и, как следствие, возможно, overkill для простых задач

Epoxy.js

First Name:

Last Name:

Full Name:

var EpoxyView = Backbone.Epoxy.View.extend({
    template: $("script[type='text/template']").html(),

    computeds: {
        fullNameDisplay: function() {
            return this.getBinding("firstName") + " " + this.getBinding("lastName");
        }
    },

    render: function() {
        this.$el.html(this.template);
        this.applyBindings();
        return this;
    }
});

var model = new Backbone.Model({ firstName: "Luke", lastName: "Skywalker" }),
    view = new EpoxyView({ model: model, el: $("#container") });

view.render();

Epoxy.js

+ -
  • Активно развивается, последний коммит - 7 дней назад
  • Computed свойства как в модели, так и во view
  • Декларировать binding'и можно как во view, так и в темплейтах
  • Возможность форматирования и конвертирования
  • Поддержка коллекций
  • Простота создания кастомных binding'ов
  • Нужно обязательно наследоваться от Backbone.Epoxy.View. Если нужна поддержка computed свойств в модели то нужно наследоваться от Backbone.Epoxy.Model

Rivets.js

First Name:

Last Name:

Full Name:

var RivetsView = Backbone.View.extend({
    template: $("script[type='text/template']").html(),
    fullName: function() {
        return this.model.get("firstName") + " " + this.model.get("lastName");
    },
    render: function () {
        this.$el.html(this.template);
        rivets.bind(this.$el, { model: this.model, view: this });
        return this;
    }
});

var model = new Backbone.Model({firstName: "Luke", lastName: "Skywalker"}),
    view = new RivetsView({model: model, el: $("#container")});

view.render();

Rivets.js

rivets.adapters[':'] = {
    observe: function(obj, keypath, callback) {
        obj.on('change:' + keypath, callback)
    },
    unobserve: function(obj, keypath, callback) {
        obj.off('change:' + keypath, callback)
    },
    get: function(obj, keypath) {
        return obj.get(keypath)
    },
    set: function(obj, keypath, value) {
        obj.set(keypath, value)
    }
};

Rivets.js

+ -
  • Активно развивается, последний коммит - 5 дней назад
  • Может использоваться как с event-driven моделями других JavaScript фреймворками (например, Stapes.js), так и с обычными JavaScript объектами
  • Computed свойства
  • Возможность форматирования и конвертирования
  • Поддержка коллекций
  • Прост в освоении
  • Для поддержки моделей и коллекций из определенного фреймворка необходимо написать адаптер
  • Дополнительная прослойка Sightglass для поддержки Observable
  • Все кастомные биндинги можно объявлять только глобально
  • IE8 не поддерживается

Knockback.js

First Name:

Last Name:

Full Name:

var KnockbackViewModel = function(model) {
    this.firstName = kb.observable(model, 'firstName');
    this.lastName = kb.observable(model, 'lastName');
    this.fullName = ko.computed((function() {
        return "" + (this.firstName()) + " " + (this.lastName());
    }), this);
};

var model = new Backbone.Model({ firstName: "Luke", lastName: "Skywalker" }),
    viewModel = new KnockbackViewModel(model);

$('#container').html($("script[type='text/template']").html());
ko.applyBindings(viewModel, $('#container')[0]);

Knockback.js

+ -
  • Активно развивается, последний коммит - 15 дней назад
  • Умеет все, что умеет Knockout.js
  • Поддержка различных Backbone.js плагинов для nested моделей (BackboneORM, Backbone-Relational etc.)
  • От самого Backbone.js остаются только Model и Router
  • Зависимость сразу от двух больших фреймворков

Выводы

  • Если хорошо знаете/нравиться Knockout.js, но нужны Backbone модели, и вы не боитесь зависимости сразу от двух больших фреймворков - ваш выбор Knockback.js
  • Если нет окончательной уверенности, что Backbone - ваш финальный выбор, то стоит обратить внимание на Rivets.js
  • Во всех остальных случаях - Epoxy.js или Backbone.Stickit

Вопросы?

Эта презентация доступна по адресу - http://tsareg.github.io/Data-binding-for-Backbone.js/, sources - https://github.com/tsareg/Data-binding-for-Backbone.js

 

Рабочие примеры находятся тут - http://tsareg.github.io/Data-binding-for-Backbone.js/samples/, sources - https://github.com/tsareg/Data-binding-for-Backbone.js/tree/master/samples

 

Презентация создана с помощью Reveal.js

Спасибо за внимание