2012-11-26 5 views
12

In meinem Backbone.Marionette Anwendung Ich habe ein Modell, das ein Id-Attribut benötigt, um seine URL zu konstruieren. Ich schaffe daher das Modell, indem es eine Id vorbei, fügen Sie ihn in eine Ansicht und dann das Modell holen:Wie kann Backbone.Marionette daran gehindert werden, eine Ansicht zu rendern, wenn das Modell nicht abgerufen wurde?

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

ich die Ansicht erwarten würde nur Rendering beginnen, sobald das Modell geholt worden ist, sondern Marionette macht das Modell Das Fehlschlagen der Schablonenausgabe wird sofort verursacht, da die erwarteten Attribute nicht vorhanden sind. Irgendwelche Problemumgehungen?

Ich versuche hier etwas Ähnliches wie die akzeptierte Antwort zu tun: Binding a Backbone Model to a Marionette ItemView - blocking .fetch()?

Aber während das mit Rückgrat funktioniert, wie in der Antwort angegeben, Marionette macht automatisch die Ansicht. siehe

auch: Backbone Marionette Displaying before fetch complete

+0

Wäre es nicht einfacher, stattdessen die 'app.content.show()' bis nach dem Fetch zu verzögern? Das würde die Wiedergabe der Ansicht verzögern, bis das Modell abgerufen wird. –

+1

Wenn Sie stattdessen eine Art von Lade-Nachricht anzeigen möchten, sehen Sie sich https://github.com/marionettejs/backbone.marionette/wiki/Displaying-A-%22loading-...%22-Message-For- A-Collection-oder-Composite-View –

Antwort

7

Wenn Sie wirklich machen verhindern wollen, bis das Modell geholt wurde, können Sie Ihre Anrufe wie diese neu anordnen sollte:

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

Alternativ sollten Sie darüber nachdenken Rendering sofort und Marionettes leeren staatlichen Support nutzen.

+1

Ich habe etwas Ähnliches benutzt, aber ich hatte gehofft, dass Marionette etwas eingebaut hat, um solche Fälle zu behandeln. Vielen Dank. –

+0

Kannst du mehr über Marionettes * leere staatliche Unterstützung * erklären? – Kevin

2

basiert auf einem von Derick Baileys Beispiele:

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

Danke, das ist im Grunde genommen dasselbe wie im Erfolgs-Handler von fetch, obwohl ich das über diesem Punkt bevorzuge. –

+0

Hallo, nicht genau, einige Male Abruf kann zurückgeben, bevor das dom gerendert wird ein Objekt kann hier helfen – danikoren

+2

Wann sind Defereds wirklich interessant ist, wenn Sie eine Ansicht nach mehreren Datenquellen fected müssen (siehe http: // davidsulc .com/blog/2013/04/02/rendering-a-view-nach-multiple-async-funktionen-return-using-promises /). Wenn Sie also einen verzögerten Aufruf verwenden, obwohl nur eine Quelle abgerufen wird, können Sie Ihren Code konsistent halten. –

10

Beide Antworten über Arbeit.
Hier ist noch eine andere Art, die ich bevorzuge (fühlt sich mehr Backboney).

Binden Sie die Ansicht direkt zum Modell
Wenn das Modell geholt getan wird, die Funktion, die Sie angeben, ausgeführt werden soll. Dies kann mit den Modellen oder Sammlungen erfolgen.

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

Dadurch können Sie auch abrufen, wann immer Sie möchten.

+2

'.show()' ruft '.render()' in der Ansicht auf, die übergeben wurde, so rät diese Methode beim Aufruf von '.show (new View)' und erneut bei 'model: sync'. – Alex

1

Ich habe neulich in das gleiche Problem laufen und entschied mich für ein Muster der Marionette Event-System, um die Ansichten ihren Status vor dem Auslösen von show() mitzuteilen. Ich benutze auch requireJS, was zusätzliche Komplexität hinzufügt - aber dieses Muster hilft!

Ich habe eine Ansicht mit einem UI-Element, das beim Klicken ein Ereignis auslöst, um eine neue Ansicht zu laden. Dies könnte eine Unteransicht oder eine Navview sein - egal.

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

Dieses Ereignis wird von dem ‚setHandlers‘ Wreqr gefangen und löst eine Sequenz Ansicht Laden (in meinem Fall eine Reihe von Logikzustandsübergängen zu handhaben ich tue). Die Sequenz 'Start' fügt die neue Ansicht ein und übergibt die erforderlichen Optionen.

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

Dann behandelt die Ansicht, die geladen wird, die Sammlungen/Modelle und ruft beim Initialisieren ab. Die Ansicht wartet auf Modell-/Auflistungsänderungen und löst dann ein neues "ready" -Ereignis mit dem Befehl wreqr executhre aus.

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

ich einen anderen Handler haben, dass bereit Ereignis fängt (und Optionen, einschließlich der Ansicht opject Referenz) und die Show auslöst().

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; 

Ich werde versuchen, einen anständigen Kern des gesamten Systems zu schreiben und hier in der nächsten Woche veröffentlichen oder so.

Verwandte Themen