3

我正在使用 Backbone 来管理 HTML 表单的状态。模型的作用是处理验证。View 的作用是包装 HTML 表单并响应模型发出的changeor事件。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;

    }
});
4

1 回答 1

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")) { ... }
于 2012-07-09T21:57:47.880 回答