2013-07-03 38 views
3

我现在正在搞乱Backbone几个星期,并基于教程做了一些简单的应用程序。现在我又一次从头开始尝试使用Backbone提供的不错功能,因为我应该这样做。BackboneJS:查看呈现良好,但刷新与未定义的集合

尽管如此,我的看法仍然存在。当页面加载时,它呈现良好,并通过迭代集合来创建其嵌套视图。 当我再次调用render()来刷新仅仅一个条目的整个列表时,所有视图属性似乎都是未定义的。

单个条目的模式:

Entry = Backbone.Model.extend({ 
}); 

条目的列表:(json.html是dataside占位符)

EntryCollection = Backbone.Collection.extend({ 
    model: Entry, 
    url: 'json.html' 
}); 

var entries = new EntryCollection(); 

查看单个项,填补下划线模板并且在模型改变时应该重新呈现自己。

EntryView = Backbone.View.extend({ 
    template: _.template($('#entry-template').html()), 
    initialize: function(){ 
     this.model.on('change', this.render); 
    }, 
    render: function(){ 
     this.$el.html(this.template(this.model.toJSON())); 
     return this; 
    } 
}); 

查看条目的整个列表这使得每个项目一个EntryView集合中,应重新渲染本身,如果添加一个新的项目。该按钮用于测试目的。现在

EntryListView = Backbone.View.extend({ 
    tagName: 'div', 
    collection: entries, 
    events: { 
     'click button': 'addEntry' 
    }, 
    initialize: function(){ 
     this.collection.on('add',this.render); 
    }, 
    render: function(){ 
     this.$el.append('<button>New</button>'); //to test what happens when a new item is added 
     var els = []; 
     this.collection.each(function(item){ 
      els.push(new EntryView({model:item}).render().el); 
     }); 
     this.$el.append(els); 
     $('#entries').html(this.el); 
     return this; 
    }, 
    addEntry: function(){ 
     entries.add(new Entry({ 
      title: "New entry", 
      text: "This entry was inserted after the view was rendered" 
     })); 
    } 
}); 

,如果我从服务器获取的收集,视图渲染罚款:

entries.fetch({ 
    success: function(model,response){ 
     new EntryListView().render(); 
    } 
}); 

当我按一下按钮,一个项目上EntryListView添加到集合中,事件处理程序捕获'add'事件并调用render()。但是如果我在渲染函数中设置了一个断点,我可以看到所有的属性看起来都是“未定义的”。没有el,没有collection ...

我在哪里出错了? 感谢您的帮助,

罗伯特

回答

4

原样,EntryListView.render不绑定到特定的上下文,这意味着范围(this)是由主叫方设置:当您点击此按钮,这是设置为你的收藏。与_.bindAll应用on

initialize: function(){ 
    this.collection.on('add', this.render, this); 
}, 
  • 当绑定你的render功能,以您的观点

    1. 指定正确的上下文中的第三个参数:

      你有多种选择,以解决您的问题

      initialize: function(){ 
          _.bindAll(this, 'render'); 
          this.collection.on('add', this.render); 
      }, 
      
    2. 使用listenTo称为

      initialize: function(){ 
          this.listenTo(this.collection, 'add', this.render); 
      }, 
      
    3. 时候给你的函数正确的上下文

    你通常会做2或/和3,_.bindAll给你一个保证的情况下,已经当你摧毁你的意见加入listenTo好处

    initialize: function(){ 
        _.bindAll(this, 'render'); 
        this.listenTo(this.collection, 'add', this.render); 
    }, 
    

    如果我可以:

    • 不以获取回调创建主视图,把它引用的地方,所以你可以在以后的时间
    • 不申报的集合/模型对你的看法原型操纵它,他们作为参数传递
    • 不硬连线的DOM元素在你的意见,它们作为参数传递

    喜欢的东西

    var EntryListView = Backbone.View.extend({ 
        events: { 
         'click button': 'addEntry' 
        }, 
        initialize: function(){ 
         _.bindAll(this, 'render'); 
         this.listenTo(this.collection, 'reset', this.render); 
         this.listenTo(this.collection, 'add', this.render); 
        }, 
        render: function(){ 
         var els = []; 
         this.collection.each(function(item){ 
          els.push(new EntryView({model:item}).render().el); 
         }); 
    
         this.$el.empty(); 
         this.$el.append(els); 
         this.$el.append('<button>New</button>'); 
         return this; 
        }, 
        addEntry: function(){ 
         entries.add(new Entry({ 
          title: "New entry", 
          text: "This entry was inserted after the view was rendered" 
         })); 
        } 
    }); 
    
    var view = new EntryListView({ 
        collection: entries, 
        el: '#entries' 
    }); 
    view.render(); 
    
    entries.fetch({reset: true}); 
    

    并演示http://jsbin.com/opodib/1/edit

  • +0

    非常感谢你的伟大的解释! – user2545975