backbone.js - 从click事件访问模型

时间:2011-09-21 16:18:44

标签: backbone.js

我有一个包含CellMolls CellCollection的BoardView。我从数据库中获取集合,然后创建CellViews。

这一切都在游泳,直到我尝试通过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,因为它涉及特定于电路板的逻辑。

3 个答案:

答案 0 :(得分:12)

好问题!我认为最好的解决方案是实现

  

EventBus 又名 EventDispatcher

协调应用程序不同区域之间的所有事件。

走这条路线似乎干净,松散耦合,易于实施,可扩展,实际上是由骨干文档建议的,请参阅Backbone Docs

请同时阅读有关herehere主题的更多信息,因为(即使我努力了),我自己的解释对我来说似乎有些平庸。

五步说明:

  1. 在您的主要或其他地方创建一个EventBus作为util并包含/要求

     var dispatcher = _.clone(Backbone.Events); // or _.extends 
    
  2. 向其添加一个或多个回调hanlder

     dispatcher.CELL_CLICK = 'cellClicked'
    
  3. 将一个触发器添加到childView的Eventlistener(此处:CellView)

     dispatcher.trigger(dispatcher.CELL_CLICK , this.model);
    
  4. 将监听器添加到parentView的Initialize函数(此处: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')
     }
    

答案 1 :(得分: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
        }
    });
    

    这可能有点清洁,因为它避免了上面提到的紧耦合,但我认为无论哪种方式都可行。

答案 2 :(得分:6)

我会让CellView处理click事件,但它只会触发Backbone事件:

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
    }
});