Двустороннее связывание данных в backbone.js

Я разрабатываю веб-приложение jQuery Backbone.js.
Как и в Adobe Flex, я реализовал привязку данных в двух направлениях в моем приложении для входные элементы/виджеты. Таким образом, каждый элемент ввода/виджет знает свою соответствующую модель и имя атрибута модели.
Когда пользователь нажимает вкладку или вводит, значение поля автоматически присваивается модели.

container.model.set(this.attrName, this.value, options); // command 1

В другом направлении, когда модель обновляется из бэкэнд, вид элемент ввода/виджет должен автоматически получать  обновление:

container.model.bind("change:"+ this.attrName, this.updateView, this); // command 2

Проблема заключается в следующем:
Когда пользователь нажимает Enter, и модель автоматически обновляется, также "change: abc" triggered и this.updateView вызывается не только тогда, когда новая модель бэкенд.

Мое решение до сих пор состояло в том, чтобы передать параметр "source: gui" при установке значения модели при нажатии пользователем (команда 1) и проверке этого в моем методе updateView. Но я больше не довольствуюсь этим решением.

Есть ли у кого-нибудь лучшее решение? Большое спасибо заблаговременно
Вольфганг

Обновление:
Когда опция silent: true передается, метод проверки модели не вызывается, поэтому это не помогает. См. Источник Backbone.js 0.9.2:

_validate: function(attrs, options) {
  if (options.silent || !this.validate) return true;

Ответ 1

С сайта Backbone.js:

Событие "change" будет запущено, если в качестве опции

не передано {silent: true}
options.silent = true;
container.model.set(this.attrName, this.value, options);

Update: Вы добавили новый комментарий к своему вопросу, поэтому я просто дополнил свой ответ, чтобы исправить новый вариант использования (поток проверки), который вы упомянули:

var ExtendedModel = Backbone.Model.extend({
    uiChange : false,
    uiSet: function (attributes, options, optional) {
        this.uiChange = true;
        this.set(attributes, options, optional);
        this.uiChange = false;
    }
});

var MyModel = ExtendedModel.extend({
});

var model = new MyModel();
model.on('change:name', function(){
  console.log('this.uiChange: ', this.uiChange);
});

//simulates the server side set
model.set({name:'hello'});

//simulates the ui side set you must use it to set from UI
model.uiSet({name:'hello2'});

Ответ 2

Двусторонняя привязка просто означает, что:

  • Когда свойства в модели обновляются, также пользовательский интерфейс.
  • Когда элементы пользовательского интерфейса обновляются, изменения распространяются обратно на модель.

Магистраль не имеет "запеченного" варианта реализации 2 (хотя вы, безусловно, можете сделать это с помощью прослушивателей событий)

В Backbone мы можем легко достичь варианта 1, привязав метод представления "render" к его событию "change" модели. Чтобы достичь варианта 2, вам также нужно добавить слушателя изменений в элемент ввода и вызвать model.set в обработчике.

check (jsfiddle.net/sunnysm/Xm5eH/16)jsfiddle пример с двухсторонней привязкой, настроенной в Backbone.

Ответ 3

Backbone.ModelBinder плагин отлично подходит для обеспечения двусторонней привязки данных между вашими проектами Backbone и моделями. Я написал сообщение в блоге о некоторых существенных особенностях этого плагина. Вот прямая ссылка: http://niki4810.github.io/blog/2013/03/02/new-post/

Ответ 4

Я хотел посмотреть, что должен был бы кодировать голой кости, чтобы иметь двустороннюю привязку с Backbone.js. Вот что я придумал:

var TwoWayBoundView = Backbone.View.extend({
    initialize: function(options) {
        this.options = _.defaults(options || {}, this.options);
        _.bindAll(this, "render");
        this.model.on("change", this.render, this);
        this.render();
    },

    events: {
        "change input,textarea,select": "update"
    },

    // input updated
    update: function(e) {
        this.model.set(e.currentTarget.id, $(e.currentTarget).val());
    },

    // model updated...re-render
    render: function(e) {
        if (e){
            var id = Object.keys(e.changed)[0];
            $('#'+id).val(e.changed[id]);
        }
        else{
            _.each(this.model.attributes, function(value, key){
                $('#'+key).val(value);
            });
        }
    }
});

И использование:

var model = new Backbone.Model({ prop1: "uno 1", prop2: "dos 2", prop3: "3" });
var view = new TwoWayBoundView({ 
    el: "#myContainer",
    model: model
});

Здесь jsbin для него: http://jsbin.com/guvusal/edit?html,js,console,output

Я использовал библиотеки, которые делают это, например, Epoxy.js(только 11k minified). И есть еще несколько других, которые я бы рекомендовал задолго до того, как вы использовали доказательство кода концепции выше.

Мне бы интересны потенциальные ловушки и улучшения, которые могут быть сделаны с вышеприведенным классом TwoWayBoundView (но ничего за базовое двухстороннее связывание, пожалуйста, т.е. я не > поиск дополнительных функций для добавления.)