Backbone.js验证错误出现在多个视图中

时间:2014-04-19 22:27:49

标签: javascript backbone.js

我在使用backbone.js应用程序时遇到了麻烦,我正在努力学习。我为它设置了jsfiddle

这是JavaScript:

var app = {};
$(document).ready(function() {

  app.Contact = Backbone.Model.extend({
    defaults: {
      firstName: '',
      lastName: '',
      email: ''
    },
    validate: function(attrs) {
      var errors = [];
      if (attrs.firstName.trim() == "") {
        errors.push({
          'message': 'Please enter a first name.',
          'field': 'firstName'
        });
      }
      if (attrs.lastName.trim() == "") {
        errors.push({
          'message': 'Please enter a last name.',
          'field': 'lastName'
        });
      }
      if (attrs.email.trim() == "") {
        errors.push({
          'message': 'Please enter an email address.',
          'field': 'email'
        });
      }
      if (errors.length) {
        return errors;
      } else {
        return false;
      }
    }
  });

  app.ContactList = Backbone.Collection.extend({
    model: app.Contact,
    localStorage: new Store('backbone-addressbook')
  });

  app.contactList = new app.ContactList();

  app.ContactView = Backbone.View.extend({
    tagName: 'tr',
    template: _.template($('#contact-template').html()),
    render: function() {
      this.$el.html(this.template(this.model.toJSON()));
      return this;
    },
    initialize: function() {
      this.model.on('change', this.render, this);
      this.model.on('destroy', this.remove, this);
      var self = this;
      this.model.on('invalid', function(model, errors) {
        _.each(errors, function(error, i) {
          console.log(self.el);
          $(self.el).find('[data-field="' + error.field + '"]').parent().addClass('has-error');
          $(self.el).find('[data-field="' + error.field + '"]').parent().find('.help-block').remove();
          $(self.el).find('[data-field="' + error.field + '"]').parent().append('<span class="help-block">' + error.message + '</span>');
        });
      });
      this.model.on('change', function(model, response) {
        //console.log(self.el);
        $(self.el).removeClass('editing');
        this.render;
      })
    },
    events: {
      'dblclick label': 'edit',
      'keypress .edit': 'updateOnEnter',
      'click .destroy': 'destroy',
      'click .save': 'close'
    },
    edit: function(e) {
      this.$el.addClass('editing');
      $(e.currentTarget).next('input').focus();
    },
    updateOnEnter: function(e) {
      if (e.which == 13) {
        this.close(e);
      }
    },
    close: function(e) {
      e.preventDefault();
      var updateObject = {};
      $(this.el).find('input[type="text"]').each(function() {
        node = $(this);
        updateObject[node.data('field')] = node.val();
      });
      this.model.save(updateObject, {validate: true});
    },
    destroy: function() {
      this.model.destroy();
    }
  });

  app.AppView = Backbone.View.extend({
    el: '#newContact',
    initialize: function() {
      $(this).find('.has-error').removeClass('has-error');
      $(this).remove('.help-block');
      app.contactList.on('add', this.addOne, this);
      app.contactList.fetch();
      var self = this;
      app.contactList.on('invalid', function(model, errors) {
        _.each(errors, function(error, i) {
          console.log(self.el);
          $(self.el).find('[data-field="' + error.field + '"]').parent().addClass('has-error');
          $(self.el).find('[data-field="' + error.field + '"]').parent().find('.help-block').remove();
          $(self.el).find('[data-field="' + error.field + '"]').parent().append('<span class="help-block">' + error.message + '</span>');
        });
      });
    },
    events: {
      'click .add': 'createContact'
    },
    createContact: function(e) {
      e.preventDefault();
      app.contactList.create(this.newAttributes(), {validate: true});
    },
    addOne: function(contact) {
      var view = new app.ContactView({model: contact});
      $('#contactList').append(view.render().el);
      $('form input[type="text"]').val('');
      $('form input[type="text"]').parent().removeClass('has-error');
      $('.help-block').remove();
    },
    newAttributes: function() {
      var updateObject = {};
      $(this.el).find('input[type="text"]').each(function() {
        node = $(this);
        updateObject[node.data('field')] = node.val();
      });
      return updateObject;
    },
  });

  app.appView = new app.AppView();

});

这是HTML:

<div class="container">
  <section id="addressbookapp">
      <header id="header">
          <h1>Address Book</h1>
          <div class="well">
          <form id="newContact" action="#" role="form">
              <div class="form-group">
                  <label class="control-label" for="firstName">First Name</label>
                  <input data-field="firstName" class="newFirstName form-control input-sm" type="text" />
              </div>
              <div class="form-group">
                  <label class="control-label" for="lastName">Last Name</label>
                  <input data-field="lastName" class="newLastName form-control input-sm" type="text" />
              </div>
              <div class="form-group">
                  <label class="control-label" for="email">Email Address</label>
                  <input data-field="email" class="newEmail form-control input-sm" type="text" />
              </div>
              <button class="add btn-xs">Add</button>
          </form>
          </div>
      </header>
      <section id="main">
          <table class="table table-striped">
              <caption>Double-click to edit an entry.</caption>
              <thead>
                  <tr>
                      <th>First</th>
                      <th>Last</th>
                      <th>Email</th>
                      <th></th>
                  </tr>
              </thead>
              <tbody id="contactList"></tbody>
          </table>
      </section>
  </section>
</div>
<script id="contact-template" type="text/template">
    <form action="#" role="form">
      <td>
        <label class="control-label" for="firstName"><%- firstName %></label>
        <input data-field="firstName" class="firstName input-sm edit" value="<%- firstName %>" type="text" />
      </td>
    <td>
      <label class="control-label" for="lastName"><%- lastName %></label>
      <input data-field="lastName" class="lastName input-sm edit" value="<%- lastName %>" type="text" />
    </td>
    <td>
      <label class="control-label" for="email"><%- email %></label>
      <input data-field="email" class="email input-sm edit" value="<%- email %>" type="email" />
    </td>
    <td>
      <button class="btn-xs save">Save</button>
      <button class="btn-xs destroy">Delete</button>
    </td>
  </form>
</script>

具体来说,当用户编辑列表中的条目(通过双击)时,清除输入(例如,姓氏),然后尝试保存,(正确)验证错误。问题是顶部的表单(用于创建新条目)也响应无效事件。

我的问题不仅仅是如何防止这种情况发生,而是组织事物的理想方式。这对我来说是一次学习练习,所以我要感谢任何提示 - 你看到的任何可以改进的地方。

1 个答案:

答案 0 :(得分:1)

这是由于您构建应用程序的方式:在&#34; new&#34;和&#34;编辑&#34;表单,您告诉应用程序如果集合中存在验证问题,则显示错误消息&#34;。因此,当您尝试编辑现有模型并且存在验证问题时,&#34; new&#34;表单更新以显示错误。

您需要做的是在&#34; new&#34;中使用新的(空白)模型。表单,如果没有验证则显示错误,如果它有效则将其添加到集合中。这样,两种形式的错误都由不同的机制处理,并且不会重叠。

请参阅http://jsfiddle.net/n9yq2/3/

app.AppView = Backbone.View.extend({
    el: '#newContact',
    initialize: function() {
      this.model = new app.Contact();

    // edited for brevity

    this.model.on('invalid', function(model, errors) {
        _.each(errors, function(error, i) {



createContact: function(e) {
      e.preventDefault();
        var attrs = this.newAttributes();
        if(this.model.set(attrs, {validate: true})){
          app.contactList.create(attrs);
      }
    },