2012-11-26 8 views
12

Nel mio backbone. Applicazione Marionette Ho un modello che richiede un attributo Id per costruirlo. Ho quindi creare il modello facendolo passare un ID, aggiungerlo a una vista e poi prendere il modelloCome impedire a Backbone.Marionette di eseguire il rendering di una vista se il modello non è stato recuperato?

model = new Model({_id:id})    
    view = new View({model:model})        
    app.content.show(view)              
    model.fetch() 

mi aspetterei la vista solo iniziare il rendering una volta che il modello è stato inverosimile, ma Marionette rende il modello causando immediatamente il fallimento del rendering del modello poiché gli attributi previsti non esistono. Qualche soluzione alternativa?

che sto cercando di fare qualcosa di simile per la risposta accettata qui: Binding a Backbone Model to a Marionette ItemView - blocking .fetch()?

Ma mentre che funziona con la spina dorsale, come indicato nella risposta, burattino rende automaticamente la vista.

Vedi anche: Backbone Marionette Displaying before fetch complete

+0

Non sarebbe più semplice ritardare invece il comando 'app.content.show() 'dopo il recupero? Ciò dovrebbe a tutti gli effetti ritardare il rendering della vista fino al recupero del modello. –

+1

Se invece desideri mostrare qualche tipo di messaggio di caricamento, dai uno sguardo a https://github.com/marionettejs/backbone.marionette/wiki/Displaying-A-%22loading-...%22-Message-For- A-Collection-Or-Composite-View –

risposta

7

Se veramente si vuole evitare che il rendering fino a quando il modello è stato recuperato si dovrebbe riordinare le chiamate in questo modo:

model = new Model({_id:id}); 
view = new View({model:model}); 
model.fetch({success: function() { 
    app.content.show(view); 
}); 

In alternativa, si dovrebbe pensare a rendere immediatamente e approfittando del supporto di stato vuoto di Marionette.

+1

Ho finito per usare qualcosa di simile, ma speravo che ci fosse qualcosa di costruito nella marionetta per gestire questi casi. Grazie. –

+0

Puoi spiegare di più sul supporto dello stato in bianco * di Marionette *? – Kevin

2

sulla base di uno degli esempi di Derick Bailey:

model = new Model({_id:id})    
    var fetched = model.fetch(); 

    // wait for the model to be fetched 
    $.when(fetched).then(function(){ 

    view = new View({model:model})        
    app.content.show(view)  
    }); 
+0

Grazie, questo è fondamentalmente lo stesso come gestirlo nel gestore di successo di fetch, anche se preferisco così sopra questo. –

+0

Ciao, non esattamente, alcune volte il recupero può tornare prima che venga reso un oggetto differito può aiutare qui – danikoren

+2

Dove i differimenti sono davvero interessanti è quando è necessario eseguire il rendering di una vista dopo che più fonti di dati sono state simulate (vedere http: // davidsulc .com/blog/2013/04/02/il rendering-a-view-dopo-multiple-asincrone-funzioni-ritorno-tramite-promesse /). Pertanto, l'utilizzo di un rinvio anche quando viene recuperata una sola fonte consente di mantenere il codice coerente. –

10

Entrambe le risposte di cui sopra lavoro.
Ecco un altro modo che preferisco usare (sembra più backboney).

Bind la vista direttamente al modello
Quando il modello è fatto di essere inverosimile, la funzione si specifica verrà eseguito. Questo può essere fatto con i modelli o collezioni.

var Model = Backbone.Model.extend({}); 
var model = new Model(); 
model.fetch(); 

var View = Marionette.ItemView.extend({ 
    model:model, 
    initialize: function(){ 
     this.model.bind("sync", this.render, this);// this.render can be replaced 
    }            // with your own function 
});        

app.region.show(new View);           

Questo consente inoltre di recuperare quando lo si desidera.

+2

'.show()' chiama '.render()' sulla vista che è passata così questo approccio viene eseguito una volta quando si chiama '.show (nuova vista)' e di nuovo su 'model: sync'. – Alex

1

Ho già riscontrato lo stesso problema e ho optato per un modello di utilizzo del sistema di eventi di Marionette per consentire alle viste di comunicare il loro stato prima di attivare show(). Sto anche usando requireJS che aggiunge una certa complessità aggiuntiva - ma questo modello aiuta!

Avrò una vista con un elemento dell'interfaccia utente che quando si fa clic, attiva un evento per caricare una nuova vista. Questa potrebbe essere una sottoview o una navview - non importa.

App.execute('loadmodule:start', { module: 'home', transition: 'left', someOption: 'foo' }); 

Questo evento viene catturato dal Wreqr 'setHandlers' e fa scattare una sequenza di visualizzazione di carico (nel mio caso sto facendo un po 'di logica per gestire le transizioni di stato). La sequenza "start" entra nella nuova vista e passa nelle opzioni necessarie.

var self = this; 
App.commands.setHandlers({'loadmodule:start': function(options) { self.start(options); 

Quindi la vista di caricamento gestisce le collezioni/modelli e recupera initalize. La vista ascolta le modifiche al modello/alla raccolta e quindi lancia un nuovo evento "pronto" usando il comando executre di wreqr.

this.listenTo(this.model, 'change', function(){ 
    App.execute('loadmodule:ready', { view: this, options: this.options }); 
}); 

Ho un gestore diverso che cattura quell'evento pronto (e opzioni, tra cui la vista opject di riferimento) e fa scattare lo show().

ready: function(options) { 

// catch a 'loadmodule:ready' event before proceeding with the render/transition - add loader here as well 

var self = this; 
var module = options.options.module; 
var view = options.view; 
var transition = options.options.transition; 
var type = options.options.type; 

if (type === 'replace') { 
    self.pushView(view, module, transition, true); 
} else if (type === 'add') { 
    self.pushView(view, module, transition); 
} else if (type === 'reveal') { 
    self.pushView(view, module, transition, true); 
} 

}, 


pushView: function(view, module, transition, clearStack) { 

var currentView = _.last(this.subViews); 
var nextView = App.main.currentView[module]; 
var self = this; 

var windowheight = $(window).height()+'px'; 
var windowwidth = $(window).width()+'px'; 
var speed = 400; 

switch(transition) { 
case 'left': 

    nextView.show(view); 

    nextView.$el.css({width:windowwidth,left:windowwidth}); 
    currentView.$el.css({position:'absolute',width:windowwidth,left:'0px'}); 

    nextView.$el.animate({translate: '-'+windowwidth+',0px'}, speed, RF.Easing.quickO); 
    currentView.$el.animate({translate: '-'+windowwidth+',0px'}, speed, RF.Easing.quickO, function(){ 

     if (clearStack) { 
      _.each(_.initial(self.subViews), function(view){ 
       view.close(); 
      }); 
      self.subViews.length = 0; 
      self.subViews.push(nextView); 
     } 

    }); 

break; 

cercherò di scrivere un succo decente di tutto il sistema e inserire qui la prossima settimana o giù di lì.

Problemi correlati