バックボーンを使用して HTML フォームの状態を管理しています。モデルの役割は、検証を処理することです。change
ビューの役割は、HTML フォームをラップし、モデルによって発行されたまたはerror
イベントに応答することです。
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;
}
});