3

バックボーンを使用して 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;

    }
});
4

1 に答える 1

2

ネイティブのバックボーン検証を使用して個々のフィールドを検証することはできません。

私のアプリでは、この検証プラグインを使用しています: 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 に答える