Магистраль: проверка атрибутов по одному
Мне нужно проверить форму с кучей входов в ней. И, если вход недействителен, укажите визуально в форме, что определенный атрибут недействителен. Для этого мне нужно проверить каждый элемент формы индивидуально.
У меня есть одна модель и один вид, представляющий всю форму. Теперь, когда я обновляю атрибут:
this.model.set('name', this.$name.val())
будет вызываться метод проверки на модели.
Но в этом методе я проверяю атрибуты all, поэтому при настройке атрибута выше все остальные также проверяются, и если какой-либо из них недействителен, возвращается ошибка. Это означает, что даже если мой атрибут "name" действителен, я получаю ошибки для других.
Итак, как я могу проверить только один атрибут?
Я думаю, что невозможно просто проверить один атрибут с помощью метода validate(). Одно из решений - не использовать метод validate, а вместо этого проверять каждый атрибут на событии "change". Но тогда это сделало бы много обработчиков изменений. Это правильный подход? Что еще я могу сделать?
Я также думаю, что это указывает на большую проблему в позвоночнике:
Всякий раз, когда вы используете model.set()
для установки атрибута в модели, выполняется ваш метод проверки и проверяются атрибуты all. Это кажется противоречивым, поскольку вы просто хотите, чтобы этот единственный атрибут был проверен.
Ответы
Ответ 1
Validate
используется для сохранения вашей модели в допустимом состоянии, она не позволит вам установить недопустимое значение, если вы не передадите параметр silent:true
.
Вы можете либо установить все свои атрибуты за один раз:
var M=Backbone.Model.extend({
defaults:{
name:"",
count:0
},
validate: function(attrs) {
var invalid=[];
if (attrs.name==="") invalid.push("name");
if (attrs.count===0) invalid.push("count");
if (invalid.length>0) return invalid;
}
});
var obj=new M();
obj.on("error",function(model,err) {
console.log(err);
});
obj.set({
name:"name",
count:1
});
или подтвердите их один за другим, прежде чем устанавливать их
var M=Backbone.Model.extend({
defaults:{
name:"",
count:0
},
validate: function(attrs) {
var invalid=[];
if ( (_.has(attrs,"name"))&&(attrs.name==="") )
invalid.push("name");
if ( (_.has(attrs,"count"))&&(attrs.count===0) )
invalid.push("count");
if (invalid.length>0) return invalid;
}
});
var obj=new M();
obj.on("error",function(model,err) {
console.log(err);
});
if (!obj.validate({name:"name"}))
obj.set({name:"name"},{silent:true});
Ответ 2
Недавно я создал небольшой плагин Backbone.js, Backbone.validateAll, который позволит вам проверять только атрибуты модели, которые в настоящее время сохранен/установлен, передав параметр validateAll.
https://github.com/gfranko/Backbone.validateAll
Ответ 3
Это не проблема Backbone, это не заставляет вас что-то писать валидацией. Нет смысла в проверке всех атрибутов, сохраняемых в модели, потому что обычно ваша модель не содержит недопустимых атрибутов, причина set()
не изменяет модель, если проверка не завершается с ошибкой, если вы не передадите параметр молчания, но это еще одна история, Однако, если вы выберете этот способ, валидация всегда передается только для не измененных атрибутов из-за упомянутой выше точки.
Вы можете свободно выбирать другой способ: проверить только атрибуты, которые должны быть установлены (переданы как аргумент validate()
).
Ответ 4
Вы также можете перегрузить функцию набора моделей с помощью собственной пользовательской функции, чтобы ее можно было отключить: true, чтобы избежать срабатывания проверки.
set: function (key, value, options) {
options || (options = {});
options = _.extend(options, { silent: true });
return Backbone.Model.prototype.set.call(this, key, value, options);
}
Это в основном передает {silent: true} в параметрах и вызывает функцию Backbone.Model set с помощью {silent: true}.
Таким образом, вам не придется пропускать {silent: true} в качестве параметров везде, где вы вызываете
this.model.set('propertyName', val, {silent: true})
Для валидаций вы также можете использовать плагин Backbone.Validation
https://github.com/thedersen/backbone.validation
Ответ 5
Мне пришлось внести изменения в файл backbone.validation.js, но он сделал эту задачу намного легче для меня. Я добавил фрагмент ниже к функции проверки.
validate: function(attrs, setOptions){
var model = this,
opt = _.extend({}, options, setOptions);
if(!attrs){
return model.validate.call(model, _.extend(getValidatedAttrs(model), model.toJSON()));
}
///////////BEGIN NEW CODE SNIPPET/////////////
if (typeof attrs === 'string') {
var attrHolder = attrs;
attrs = [];
attrs[attrHolder] = model.get(attrHolder);
}
///////////END NEW CODE SNIPPET///////////////
var result = validateObject(view, model, model.validation, attrs, opt);
model._isValid = result.isValid;
_.defer(function() {
model.trigger('validated', model._isValid, model, result.invalidAttrs);
model.trigger('validated:' + (model._isValid ? 'valid' : 'invalid'), model, result.invalidAttrs);
});
if (!opt.forceUpdate && result.errorMessages.length > 0) {
return result.errorMessages;
}
}
Затем я мог бы вызвать проверку на один атрибут, например:
this.model.set(attributeName, attributeValue, { silent: true });
this.model.validate(attributeName);