2011-09-21 75 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应该如何工作。还是我错了? –