如何使用Backbone.js报告无效的表单字段

时间:2012-07-09 21:37:30

标签: backbone.js validation

我正在使用Backbone来管理HTML表单的状态。 Model的作用是处理验证。 View的作用是包装HTML表单并响应模型发出的changeerror事件。

当给定字段实际有效时,Backbone似乎只发出change个事件。这导致了一些非常意想不到的行为,这让我觉得我做错了。

以下是我正在做的事情的摘要: 1.初始加载序列化表单并将其注入模型 2.当发出error事件时,我会在无效字段旁边生成错误节点。 3.当发出change事件时,我会删除(现在有效)字段旁边的错误提示。

当使用最初有效的表单呈现页面,并且用户使字段无效时,将按预期显示该消息;但是,模型从不在内部更新字段。因此,当用户更正错误时,永远不会发出change事件。

Example: Initially valid

当使用最初的无效表单呈现页面时,事情看起来工作正常......但这只是因为模型的初始属性为空。更正字段会使消息消失,但如果再次将其更改为无效状态,则消息永远不会消失。

Example: Initially invalid

我做错了什么?也许我应该使用另一种方法呢?

我的模特

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;

    }
});

1 个答案:

答案 0 :(得分:2)

您无法使用本机Backbone验证来验证单个字段。

在我的应用中,我使用此验证插件:https://github.com/thedersen/backbone.validation

然后在您的模型中为每个字段添加验证规则(它是可选的,因此您无需将其添加到所有模型中):

var NewReview = Backbone.Model.extend({
  initialize: function() {
     /* ... */
  },

  validation: {
    summary: {
      required: true,
      minLength: 10
    },
    pros: {
      required: true,
      minLength: 10
    },
    cons: {
      required: true,
      minLength: 10
    },
    overall: function(value) {
      var text = $(value).text().replace(/\s{2,}/g, ' ');
      if (text.length == 0) text = value;
      if (text.length < 20) return "Overall review is too short";
    },
    rating: {
      range: [0.5, 5]
    },
    product_id: {
      required: true
    }
  }
});

在视图或其他地方,您可以验证整个模型或单个字段:

if (this.model.validate()) { ... }

if (this.model.isValid("summary")) { ... }