Как ограничить количество событий изменения, когда установлены несколько атрибутов? - PullRequest
7 голосов
/ 26 января 2012

Я заметил, что когда несколько атрибутов модели Backbone установлены следующим образом,

model.set({
    att1:val1,
    att2:val2
});

запускаются два события изменения.Я ошибочно предполагал, что только одно событие изменения будет запущено после того, как все атрибуты будут установлены .

Это может показаться не проблемой, но это когда функция связана с att1это также использует значение att2.Другими словами, когда вы делаете это

model.bind('change:att1', func1);
...
func1 = function() {
    var att2 = model.get('att2');
}

, переменная att2 будет установлена ​​на старое значение атрибута модели att2.

Вопрос состоит в том, как предотвратить это элегантным способом.,Конечно, одним из вариантов является установка att2 перед установкой att1 или привязка к att2 (вместо att1), но кажется, что это простой вариант в простых ситуациях.Последний вариант также предполагает, что атрибуты устанавливаются в том порядке, в котором они перечислены в методе set (как мне кажется, и в этом случае).

Я сталкивался с этой проблемой несколько раз, отсюда и мой вопрос.Проблема в том, что мне потребовалось некоторое время, чтобы осознать, что на самом деле происходило.

В заключение, точно так же, как вы можете передать {silent: true} в качестве опции метода set, было бы неплохоиметь параметр {group: true} (или что-то подобное), указывающий, что события изменения должны запускаться только после того, как были установлены все атрибуты.

1 Ответ

7 голосов
/ 26 января 2012

В более сложных ситуациях я бы пошел для пользовательских событий.

вместо привязки к изменению: att1 или change: att2 я бы искал определенное пользовательское событие, которое вы запускаете после установкивсе атрибуты, которые вы хотели изменить в модели.

model.set({
    att1:val1,
    att2:val2
});
model.trigger('contact:updated'); // you can chose your custom event name yourself

model.bind('contact:updated', func1);
...
func1 = function() {
    var att2 = model.get('att2');
}

Недостатком этой идеи является добавление новой строки кода везде, где вы хотите вызвать событие.если это случается много, вы можете изменить или переопределить model.set (), чтобы сделать это за вас, но тогда вы уже меняете магистральный код, не знаю, что вы думаете по этому поводу.

РЕДАКТИРОВАТЬ

после просмотра исходного кода магистрали, я заметил, что событие change запускается сразу после срабатывания change:attribute.(доказано фрагментом ниже)

// Fire `change:attribute` events.
for (var attr in changes) {
  if (!options.silent) this.trigger('change:' + attr, this, changes[attr], options);
}

// Fire the `"change"` event, if the model has been changed.
if (!alreadyChanging) {
  if (!options.silent && this._changed) this.change(options);
  this._changing = false;
}

, тогда как this.change(options); относится к этому:

change: function(options) {
  this.trigger('change', this, options);
  this._previousAttributes = _.clone(this.attributes);
  this._changed = false;
},

, так что если вы будете привязываться к событию change вместо конкретногоchange:argument событие, вы получите функцию обратного вызова после того, как оба (или все) атрибуты будут изменены.

Единственный недостаток - он активируется при ЛЮБОМ изменении, даже если вы измените третий или четвертый атрибут.вам нужно посчитать, что в ...

небольшой пример того, как это работает на jsfiddle http://jsfiddle.net/saelfaer/qm8xY/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...