【问题标题】:Backbone JS add extended model to a collection of its inherited model typeBackbone JS 将扩展模型添加到其继承模型类型的集合中
【发布时间】:2013-07-16 17:46:29
【问题描述】:

我刚刚开始深入研究backboneJS,并且已经开始在codepen 中构建一个小型文本应用程序(http://codepen.io/azaslavsky/pen/fJghE)。一切都很顺利,除了我有一个问题:一旦用户点击提交按钮,我希望表单容器视图:

  1. 解析所有表单域。这些是多种模型类型(标题字段、所见即所得的文本编辑器等),以及一个集合(tagInput.collection - 用户放入的所有标签)
  2. 为用户提供给应用的所有这些数据创建一个标准化的 JSON 对象,以将其传递给服务器

目前,我正在尝试将 Backbone.Model 扩展为一个新的类“FormModel”,该类仅包含默认属性“value”。然后,我在我的主容器上创建了一个新集合,其中包括容器内的所有各种模型。因此,container.collection 的模型是 FormModel,但我尝试 .add() 的所有实际模型都是 FormModel 的扩展类。这可能吗?每当我尝试访问该集合时,它总是空的!我觉得我错过了理解底层逻辑指导骨干的一些关键部分,但我不能确切地说是什么!

(我认为是)相关代码附在下面。我的“迷你应用”最新版本的完整代码也在上面链接:

//LINE 9 in Full Code
// Generic, very simply model type for any type of form entry that we can extend
  var FormModel = Backbone.Model.extend({
    defaults: {
      value: '',
    }
  });

  //Input class definition
  var input = {};
  input.model = FormModel.extend({
    defaults: {
      placeHolder: 'Enter Title Here...',
      class: '',
      warn: 'a title',
      size: '20px'
    }
  });
  input.view = Backbone.View.extend({
    events: {
      'keypress input': 'checkKey',
      'change input': 'updateValue'
    },
    initialize: function() {
      _.bindAll(this, 'render', 'checkKey', 'doSubmit','updateValue');
      this.render();
    },
    render: function() {
      if (this.model.get('class')) {
        $(this.el).addClass(this.model.get('class'));
      }
      $(this.el).append('<div class="clearButton inputClear"></div>');
      $(this.el).append('<input type="text" placeHolder="'+this.model.get('placeHolder')+'" style="font-size: '+this.model.get('size')+'">');
      this.clickable = true;
      return this;
    },
    checkKey: function(e) {
      if (e.keyCode === 13) {
        this.doSubmit();
      }
    },
    doSubmit: function() {
      var thisVal = this.updateValue();
      if (thisVal.length > 0) {
      } else {
        alert('Hey, you need to '+this.model.get('warn')+' before you can submit this post!');
      }
    },
    updateValue: function() {
      var thisVal  = $('input', this.el).val();
      this.model.set('value', thisVal);
      return thisVal;
    },
  });



/*
 *[...]
 */



//LINE 132 in Full Code
//Tag class definition
  var tag = {};
  tag.model = FormModel.extend({
    defaults: {
      title: '',
      exists: false,
      parent: $('#container'),
    }
  });
  tag.view = Backbone.View.extend({
    events: {
      'click .clearButton': 'kill',
    },
    initialize: function() {
      _.bindAll(this, 'render', 'kill');
      this.render();
    },
    render: function() {
      $(this.el).addClass('tagRow');
      $(this.el).html(this.model.get('title'));
      $(this.el).append('<div class="clearButton tagClose"></div>');
      this.clickable = true;
      return this;
    },
    kill: function() {
      if (this.clickable) {
        this.clickable = false;
        var that = this;
        $(this.el).animate({opacity: 0}, 500, function(){
          $(that.el).remove();
          this.model.destroy();
        });
      }
    }
  });
  tag.collection = Backbone.Collection.extend({
    model: tag.model,
  });



/*
 *[...]
 */



//LINE 214 in Full Code
  //Container class definition
  var container = {};
  container.collection = Backbone.Collection.extend({
    model: FormModel
  });
  container.model = Backbone.Model.extend({
  });
  container.view = Backbone.View.extend({
    el: $('body'),
    initialize: function() {
      _.bindAll(this, 'render', 'appendItem', 'newTag', 'makeTagDialog', 'validate');
      this.collection = new container.collection();
      this.fields = [];
      this.render();
    },
    render: function() {
      $('body').append('<div id="container"></div>');
      this.container = $('body #container');

      var title = new input.model({
        placeHolder: 'Enter Title Here...',
        class: 'subArea titleArea',
        warn: 'a title',
      });
      this.appendItem(new input.view({model: title}).el);

      this.appendItem(new editor.view({model: new editor.model()}).el);
      this.makeTagDialog();

      var submitButton = new submit.view({model: new submit.model()});
      this.listenTo(submitButton.model, 'change:counter', this.validate);
      $(this.container).append(submitButton.el);

      return this;
    },
    appendItem: function(view) {
      this.collection.add(view.model);
      $(this.container).append(view);
    },
    makeTagDialog: function() {
      this.container.append('<div class="subArea tagDialog"></div>');
      var tags = $('.tagDialog', this.container);
      tags.append('<div class="tagArea"></div>');
      var tagInput = new input.view({
        model: new input.model({ 
          placeHolder: 'Tag Your Post...',
          class: 'tagInput',
          warn: 'at least one tag',
          size: '16px',
          value: ''
        })
      });
      tagInput.addTag = function() {
        if (this.model.get('value').length) {
          this.collection.add(new tag.model({
            title: this.model.get('value')
          }));
        }
        this.clearInput();
      };
      tagInput.model.on('change:value', tagInput.addTag, tagInput);
      this.appendItem(tagInput.el);
      $('.tagInput .clearButton').css('marginTop', '-2px');

      tagInput.collection = new tag.collection();
      tagInput.collection.on('add', this.newTag);
    },
    newTag: function(model) {
        thisView = new tag.view({model: model});
        thisView.parent = this;
        $('.tagArea', this.container).append(thisView.el);
    },
    validate: function(){
      alert('Form validation launched!');
      var form = [];
      this.collection.each(function(value) {
        form.push(value);
      });
    }
  });

new container.view({model: container.model});
})(jQuery);

【问题讨论】:

    标签: javascript backbone.js backbone.js-collections class-extensions


    【解决方案1】:

    问题在于 appendItem 方法。 你这样称呼它:

    this.appendItem(new input.view({model: title}).el);
    

    但是通过这种方式,您将视图 el 作为参数传递,而不是视图本身,因此 view.model 是未定义的!

    你应该用这种方式重构 appendItem:

    appendItem: function(view) {
        this.collection.add(view.model);
        $(this.container).append(view.el);
    },
    

    并称它为:

    this.appendItem(new editor.view({model: new editor.model()}));
    

    【讨论】:

    • 你是一个美丽的人。我的第一个孩子将被命名为 Ingro 或 Ingria,具体取决于性别。
    • 很高兴我能帮上忙!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-19
    • 2013-08-02
    • 1970-01-01
    • 2019-12-26
    • 2012-07-19
    相关资源
    最近更新 更多