Двустороннее связывание данных в 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 (но ничего за базовое двухстороннее связывание, пожалуйста, т.е. я не > поиск дополнительных функций для добавления.)