2011-09-21 17 views
9

Ho un BoardView contenente un CellCollection di CellModels. Prendo la raccolta dal db e quindi creo le CellViews.backbone.js - accesso a un modello da un evento click

Questo funziona perfettamente finché non provo ad accedere a un CellModel tramite un evento click sul BoardView. Non riesco affatto a raggiungere i modelli sottostanti ... solo i punti di vista. C'è un modo per fare questo?

ho tentato di includere il codice specifico in basso:

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

ho bisogno il clic su "accadere" sul BoardView, non il CellView, perché si tratta di logica specifica di bordo.

risposta

11

Mi vengono in mente almeno due approcci si potrebbe utilizzare qui:

  1. Passare il BoardView al CellView in fase di inizializzazione, e quindi gestire l'evento nel 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 
        } 
    }); 
    

    Questo funzionerebbe, ma preferisco non avere punti di vista che chiamino i metodi l'uno dell'altro, in quanto li rende più strettamente accoppiati.

  2. allegare l'ID CellModel al DOM quando si esegue il rendering è:

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

    Questo è probabilmente un po 'più pulito, in quanto evita l'accoppiamento stretto di cui sopra, ma credo che in entrambi i casi avrebbe funzionato.

+0

OP qui. entrambe le soluzioni hanno funzionato alla perfezione ... e il n. 1 è perfetto per i miei scopi. grazie mille. –

+0

Ottimo - se sei soddisfatto della risposta, puoi accettarlo facendo clic sulla casella di controllo sotto il punteggio :). – nrabinowitz

+6

Soluzione 2, a mio parere, non è una buona idea. L'intero punto di Backbone è quello di ottenere dati dal server e renderli nella vista client, e non di ottenere dati dalla vista e di rimandarli indietro. Funziona, ma non è un bel modo. – sntran

12

Buona domanda! Penso che la soluzione migliore sarebbe quella di implementare un

EventBus alias EventDispatcher

di coordinare tutti gli eventi tra le diverse aree della vostra applicazione.

Andando questa strada sembra pulita, loosely coupled, facile da implementare, estensibile ed è in realtà suggerito dalla documentazione spina dorsale, vedere Backbone Docs

Si prega inoltre di leggere di più sul tema here e here perché (anche se ho provato difficile) la mia spiegazione mi sembra abbastanza mediocre.

Cinque passo spiegazione:

  1. Creare un EventBus nel vostro principale o da qualche altra parte come un util e comprendono/lo richiedono

    var dispatcher = _.clone(Backbone.Events); // or _.extends 
    
  2. aggiungere una o più richiamata hanlder (s) ad esso

    dispatcher.CELL_CLICK = 'cellClicked' 
    
  3. Aggiungi un trigger per l'EventListener del childView (qui: la CellView)

    dispatcher.trigger(dispatcher.CELL_CLICK , this.model); 
    
  4. aggiungere un listener alla funzione di inizializzazione del parentView (qui: la BoardView)

    eventBus.on(eventBus.CARD_CLICK, this.cardClick); 
    
  5. Definire la richiamata corrispondente all'interno della vostra parentView (e aggiungerlo al tuo _.bindAll)

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

avrei lasciato il CellView gestire l'evento click, ma sarà solo grilletto 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

Bella soluzione ... ma ci sono alcuni errori nel codice. 1. view.bind ('cellClicked' this.analyzeCellClick) 2. Basta provare il contesto che otteniamo in analyzeCellClick. Sarà di vista perché questo metodo è attivato da cellview Quindi piuttosto usare chiusure o usare Function.bind. – sachinjain024

+0

Grazie @ Blunderboy! – sntran

+0

questo approccio sembra più coerente con il modo in cui capisco come dovrebbe funzionare Backbone. o mi sbaglio? –

Problemi correlati