2011-09-21 15 views
9

Tengo un BoardView que contiene una CellCollection de CellModels. Recojo la colección de la base de datos y luego creo las vistas de celda.backbone.js - acceder a un modelo desde un evento de clic

Todo esto funciona muy bien hasta que intento acceder a un modelo de celda mediante un evento de clic en el BoardView. No puedo llegar a los modelos subyacentes ... solo los puntos de vista. ¿Hay alguna forma de hacer esto?

He intentado incluir el código correspondiente a continuación:

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) { 
     // ????????? 
    } 
}); 

necesito el clic a "pasar" en la BoardView, no el CellView, porque se trata de la lógica específica de a bordo.

Respuesta

11

puedo pensar en por lo menos dos enfoques que podría utilizar aquí:

  1. Pasar el BoardView a la CellView en la inicialización, y luego controlar el evento en el 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 
        } 
    }); 
    

    Este funcionaría, pero prefiero no tener vistas llamar a los métodos de los demás, ya que los hace más estrechamente unidos.

  2. atar la identificación CellModel al DOM cuando se realice un renderizado:

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

    Esto es probablemente un poco más limpio, ya que evita el estrecho acoplamiento mencionado anteriormente, pero creo que de cualquier manera iba a funcionar.

+0

OP aquí. Ambas soluciones funcionaron sin problemas ... y la # 1 es perfecta para mis propósitos. muchas gracias. –

+0

Excelente: si está contento con la respuesta, puede aceptarla haciendo clic en la casilla debajo del puntaje :). – nrabinowitz

+6

Solución 2, en mi opinión, no es una buena idea. El objetivo de Backbone es obtener datos del servidor y representarlos en la vista del cliente, y no obtener datos de la vista y enviar de vuelta. Funciona, pero no es una buena forma. – sntran

12

¡Buena pregunta! Creo que la mejor solución sería implementar un

EventBus aka EventDispatcher

para coordinar todos los eventos entre las diferentes áreas de su aplicación.

ir por ese camino parece limpia, débilmente acoplado, fácil de implementar, extensible y en realidad es sugerido por la documentación de la columna vertebral, ver Backbone Docs

Por favor, también leer más sobre el tema here y here debido a que (a pesar de que he intentado difícil) mi propia explicación parece algo mediocre para mí.

de cinco pasos explicación:

  1. Crear EventBus en su principal o en otro lugar como una util e incluyen/requiere que

    var dispatcher = _.clone(Backbone.Events); // or _.extends 
    
  2. Añadir una o más hanlder devolución de llamada (s) a él

    dispatcher.CELL_CLICK = 'cellClicked' 
    
  3. Añadir un disparador para la eventListener de su childView (aquí: el CellView)

    dispatcher.trigger(dispatcher.CELL_CLICK , this.model); 
    
  4. añadir un detector a la función de inicialización de su parentView (aquí: el BoardView)

    eventBus.on(eventBus.CARD_CLICK, this.cardClick); 
    
  5. Definir la devolución de llamada correspondiente dentro de su parentView (y añadirlo a su _.bindAll)

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

que iba a dejar la CellView controlar el evento clic, pero se acaba de gatillo un evento 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 
    } 
}); 
+1

Buena solución ... Pero hay algunos errores en su código. 1. view.bind ('cellClicked' this.analyzeCellClick) 2. Solo prueba el contexto que obtenemos en analyzeCellClick. Será visible porque este método se desencadena por la vista de celda. En su lugar, utilice cierres o utilice Function.bind. – sachinjain024

+0

¡Gracias @blunderboy! – sntran

+0

este enfoque parece ser más consistente con la forma en que entiendo cómo se supone que el Backbone funciona. o estoy equivocado? –

Cuestiones relacionadas