2013-07-03 36 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