2011-09-21 71 views
9

我有一個包含CellCollection CellModels的BoardView。我從數據庫獲取集合,然後創建CellViews。backbone.js - 從點擊事件訪問模型

這一切都在順利進行,直到我嘗試通過BoardView上的單擊事件訪問CellModel爲止。我根本無法得到底層模型......只有意見。有沒有辦法做到這一點?

我已經嘗試包括以下相關代碼:

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

CellCollection = Backbone.Collection.extend({ 
    model : CellModel 
}); 

CellView = Backbone.View.extend({ 
    className : 'cell', 
}); 

BoardView = Backbone.View.extend({ 
    this.model.cells = new CellCollection(); 

    render : function() { 
     this.cellList = this.$('.cells'); 
     return this; 
    }, 

    allCells : function(cells) { 
     this.cellList.html(''); 
     this.model.cells.each(this.addCell); 
     return this; 
    }, 

    addCell : function(cell) { 
     var view = new Views.CellView({ 
      model : cell 
     }).render(); 

     this.cellList.append(view.el); 
    }, 

    events : { 
     'click .cell' : 'analyzeCellClick', 
    }, 

    analyzeCellClick : function(e) { 
     // ????????? 
    } 
}); 

我需要點擊BoardView,而不是CellView爲「發生」,因爲它涉及特定板的邏輯。

回答

11

我想你可能在這裏使用至少兩種方法:

  1. 傳遞BoardView在初始化CellView,然後處理在CellView事件:

    var CellView = Backbone.View.extend({ 
        className : 'cell', 
    
        initialize: function(opts) { 
         this.parent = opts.parent 
        }, 
    
        events : { 
         'click' : 'analyzeCellClick', 
        }, 
    
        analyzeCellClick : function() { 
         // pass the relevant CellModel to the BoardView 
         this.parent.analyzeCellClick(this.model); 
        } 
    }); 
    
    var BoardView = Backbone.View.extend({ 
        // ... 
    
        addCell : function(cell) { 
         var view = new Views.CellView({ 
          model : cell, 
          parent : this 
         }).render(); 
    
         this.cellList.append(view.el); 
        }, 
    
        analyzeCellClick : function(cell) { 
         // do something with cell 
        } 
    }); 
    

    這會工作,但我寧願沒有意見調用彼此的方法,因爲它使他們更緊密耦合。

  2. 附上CellModel ID的DOM,當你使它:

    var CellView = Backbone.View.extend({ 
        className : 'cell', 
    
        render: function() { 
         $(this.el).data('cellId', this.model.id) 
         // I assume you're doing other render stuff here as well 
        } 
    }); 
    
    var BoardView = Backbone.View.extend({ 
        // ... 
    
        analyzeCellClick : function(evt) { 
         var cellId = $(evt.target).data('cellId'), 
          cell = this.model.cells.get(cellId); 
         // do something with cell 
        } 
    }); 
    

    這可能是一個少許清潔劑,因爲它避免了上面提到的緊耦合的,但我認爲無論哪種方式會工作。

+0

OP在這裏。兩個解決方案都完美無缺地工作......並且#1對於我的目的來說是完美的。非常感謝。 –

+0

太好了 - 如果您對答案感到滿意,您可以點擊分數下方的複選框來接受它:)。 – nrabinowitz

+6

解決方案2在我看來並不是一個好主意。 Backbone的重點是從服務器獲取數據並將其呈現在客戶端視圖中,而不是從視圖中獲取數據併發回。它有效,但它不是一個好方法。 – sntran

12

好問題!我認爲最好的解決辦法是實施

EventBus又名此事件

協調應用程序的不同區域之間的所有事件。

走這樣一條路看起來乾淨,鬆耦合,易於實現,可擴展的,它實際上是由骨幹文件建議,看Backbone Docs

也請閱讀更多關於該主題herehere因爲(即使我試着很難)我自己的解釋對我來說似乎有點平庸。

五步解釋:

  1. 在主或其他地方作爲一個實用程序創建一個EventBus,包括/需要它

    var dispatcher = _.clone(Backbone.Events); // or _.extends 
    
  2. 添加一個或多個回調hanlder (s)

    dispatcher.CELL_CLICK = 'cellClicked' 
    
  3. 觸發添加到您的childView的事件監聽(這裏的CellView)

    dispatcher.trigger(dispatcher.CELL_CLICK , this.model); 
    
  4. 添加監聽到你的parentView的初始化函數(這裏的BoardView)

    eventBus.on(eventBus.CARD_CLICK, this.cardClick); 
    
  5. 定義你parentView內相應的回調(並將其添加到您的_.bindAll)

    cellClicked: function(model) { 
    // do what you want with your data here 
    console.log(model.get('someFnOrAttribute') 
    } 
    
6

我先給CellView處理click事件,但它只會觸發骨幹事件:

var CellView = Backbone.View.extend({ 
    className : 'cell', 

    initialize: function() { 
     _.bindAll(this, 'analyzeCellClick'); 
    } 

    events : { 
     'click' : 'analyzeCellClick', 
    }, 

    analyzeCellClick : function() { 
     this.trigger('cellClicked', this.model); 
    } 
}); 

var BoardView = Backbone.View.extend({ 
    // ... 

    addCell : function(cell) { 
     var view = new Views.CellView({ 
      model : cell 
     }).render(); 

     this.cellList.append(view.el); 
     view.bind('cellClicked', function(cell) { 
       this.analyzeCellClick(cell); 
      }; 
    }, 

    analyzeCellClick : function(cell) { 
     // do something with cell 
    } 
}); 
+1

不錯的解決方案..但是在你的代碼中幾乎沒有錯誤。 1. view.bind('cellClicked'this.analyzeCellClick) 2.試試我們在analyzeCellClick中獲得的上下文。這將是看法,因爲這種方法是由cellview觸發所以,而是使用閉包或使用Function.bind。 – sachinjain024

+0

謝謝@blunderboy! – sntran

+0

這種方法似乎更符合我如何理解Backbone應該如何工作。還是我錯了? –