我正在使用 Backbone 来管理 HTML 表单的状态。模型的作用是处理验证。View 的作用是包装 HTML 表单并响应模型发出的change
or事件。error
Backbone 似乎只change
在给定字段实际有效时才发出事件。这导致了一些非常出乎意料的行为,让我觉得我做错了。
以下是我正在做的总结: 1. 初始加载序列化表单并将其注入模型 2.error
发出事件时,我在无效字段旁边生成错误节点。3.change
发出事件时,我删除(现在有效)字段旁边的错误注释。
当页面以最初有效的表单呈现时,并且用户使字段无效,则消息按预期显示;但是,模型从不在内部更新该字段。因此,当用户更正错误时,change
永远不会发出事件。
当页面以最初无效的形式呈现时,事情似乎工作正常......但这只是因为模型的初始属性是空的。更正该字段会使消息消失,但如果您再次将其更改为无效状态,则消息永远不会消失。
我究竟做错了什么?也许我应该使用另一种方法?
我的模特
var Foo = Backbone.Model.extend({
validate: function(attr) {
var errors = {};
if (_.isEmpty(attr)) return;
if (attr.foo && attr.foo != 123) {
errors.foo = ['foo is not equal to 123'];
}
if (attr.bar && attr.bar != 456) {
errors.bar = ['bar is not equal to 456'];
}
return _.isEmpty(errors) ? undefined : errors;
}
});
我的观点
FooForm = Backbone.View.extend({
events: {
'change :input': 'onFieldChange'
},
initialize: function(options) {
this.model.on('error', this.renderErrors, this);
this.model.on('change', this.updateFields, this);
// Debugging only
this.model.on('all', function() {
console.info('[Foo all]', arguments, this.toJSON())
});
this.model.set(this.serialize());
},
onFieldChange: function(event) {
var field = event.target,
name = field.name,
value = field.value;
this.model.set(name, value);
},
renderErrors: function(model, errors) {
_.each(errors, function(messages, fieldName) {
var el = $('#' + fieldName),
alert = $('<div/>').addClass('error');
el.parent().find('.error').remove();
_.each(messages, function(message) {
alert.clone().text(message).insertAfter(el);
});
});
},
updateFields: function(model, options) {
if (!options || !options.changes) return;
_.each(_.keys(options.changes), function(fieldName) {
var el = $('#' + fieldName);
el.parent().find('.error').remove();
});
},
serialize: function() {
var raw = this.$el.find(':input').serializeArray(),
data = {},
view = this;
$.each(raw, function() {
// Get the model's field name from the form field's name
var name = this.name;
if (data[name] !== undefined) {
if (!data[name].push) {
data[name] = [data[name]];
}
data[name].push(this.value || '');
}
else {
data[name] = this.value || '';
}
});
return data;
}
});