2012-11-26 12 views
12

W aplikacji backbone.Marionette mam model, który wymaga atrybutu Id do skonstruowania jego adresu URL. Dlatego stworzenie modelu przekazując mu identyfikator, dodaj go do widoku i następnie pobrać model:Jak zapobiegać renderowaniu widoku Backbone.Marionette, jeśli jego model nie został pobrany?

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

spodziewałbym widok, aby rozpocząć dopiero renderowania gdy model został naciągane, ale Marionette renderuje modelu natychmiast powodując niepowodzenie wyświetlania mojego szablonu, ponieważ oczekiwane atrybuty nie istnieją. Jakiekolwiek obejścia?

Próbuję zrobić coś podobnego z przyjętym odpowiedź tutaj: Binding a Backbone Model to a Marionette ItemView - blocking .fetch()?

Ale jednocześnie, że współpracuje z kręgosłupem, jak stwierdził w odpowiedzi, Marionette automatycznie renderuje widoku.

zobacz także: Backbone Marionette Displaying before fetch complete

+0

Czy nie byłoby łatwiej opóźnić 'app.content.show()' do momentu pobrania? To by spowodowało opóźnienie renderowania widoku do czasu, aż model zostanie pobrany. –

+1

Jeśli zamiast tego chcesz pokazać wiadomość ładującą, zajrzyj na https://github.com/marionettejs/backbone.marionette/wiki/Displaying-A-%22loading-...%22-Message-For- A-Collection-Or-Composite-View –

Odpowiedz

7

Jeśli naprawdę chcesz, aby zapobiec renderowania aż model został pobrana należy zmienić kolejność połączeń tak:

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

Alternatywnie, należy zastanowić się natychmiast renderowania i korzystając z pustego wsparcia ze strony marionetki.

+1

Skończyło się na tym, że używałem czegoś podobnego, ale miałem nadzieję, że w marionetce jest coś takiego, co radzi sobie z takimi przypadkami. Dzięki. –

+0

Czy możesz wyjaśnić więcej * pustej pomocy państwa * marionetki *? – Kevin

2

oparty na jednym z przykładów 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

Dzięki, to jest w zasadzie to samo, co obsługa w procedurze pobierania, ale ja wolę nad tym. –

+0

Cześć, niezupełnie, czasami pobieranie może powrócić przed renderowaniem obiektu odroczonego obiektu może pomóc tutaj – danikoren

+2

Gdzie odroczenia są naprawdę interesujące, gdy trzeba renderować widok po tym, jak wiele źródeł danych zostało przetworzonych (zobacz http: // davidsulc .com/blog/2013/04/02/rendering-a-view-after-multiple-async-functions-return-using-promises /). Korzystanie z odroczonego nawet wtedy, gdy pobierane jest tylko jedno źródło, pozwala zachować spójność kodu. –

10

Obie odpowiedzi Powyższe pracy.
Oto kolejny sposób, który preferuję (więcej backboney).

Bind widok bezpośrednio do modelu
Kiedy model jest zrobione są naciągane, funkcja określić zostanie uruchomiony. Można to zrobić w kolekcjach modeli lub.

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

Umożliwia to również pobieranie w dowolnym momencie.

+2

'.show()' wywołuje '.render()' w widoku, który został przekazany, więc to podejście renderuje się raz, gdy wywołuje się '.show (nowy widok)' i ponownie na 'model: sync'. – Alex

1

Zapomniałem o tym, że uruchomiłem ten sam problem i ustaliłem schemat korzystania z systemu zdarzeń Marionetki, aby widoki przekazały swój status przed uruchomieniem programu show(). Używam również requireJS, który dodaje dodatkową złożoność - ale ten wzór pomaga!

Będę mieć jeden widok z elementem interfejsu, który po kliknięciu wywoła zdarzenie, aby załadować nowy widok Może to być subview lub navview - nie ma znaczenia.

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

To zdarzenie jest złapany przez Wreqr „setHandlers” i uruchamia sekwencję widok ładowania (w moim przypadku robię sporo logiki do obsługi przejścia między stanami). Sekwencja "start" pojawia się w nowym widoku i przekazuje niezbędne opcje.

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

Następnie widok ładujący obsługuje kolekcje/modele i pobieranie podczas initalize. Widok nasłuchuje zmian modelu/kolekcji, a następnie uruchamia nowe "gotowe" zdarzenie za pomocą komendy execqr's.

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

Mam inny obsługi, że połowy że gotowy zdarzeń (i opcje, w tym widoku opject odniesienia) i wyzwala 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; 

Spróbuję napisać porządny sens całego systemu i opublikować go w przyszłym tygodniu.