Магистраль: проверка атрибутов по одному

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

У меня есть одна модель и один вид, представляющий всю форму. Теперь, когда я обновляю атрибут:

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);