Подтвердить что ты не робот

Как предотвратить отображение Backbone.Marionette, если модель не была выбрана?

В моем backbone.Marionette приложении у меня есть модель, для которой требуется атрибут Id для его создания. Поэтому я создаю модель, передавая ее Id, добавляю ее в представление и затем извлекаю модель:

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

Я бы ожидал, что представление начнет рендеринг только после того, как модель будет извлечена, но Marionette отображает модель, которая немедленно приводит к тому, что моя рендеринг шаблона не выполняется, поскольку ожидаемые атрибуты не существуют. Любые обходные пути?

Я пытаюсь сделать что-то похожее на принятый ответ здесь: Связывание базовой модели с марионеткой ItemView - блокировка .fetch()?

Но пока это работает с позвоночником, как указано в ответе, Marionette автоматически отображает представление.

Также смотрите: Магическая сетка Макросъемка Отображение перед завершением выборки

4b9b3361

Ответ 1

Если вы действительно хотите предотвратить показ до тех пор, пока модель не будет выбрана, вы должны изменить порядок своих вызовов следующим образом:

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

В качестве альтернативы вы должны сразу подумать об рендеринге и воспользоваться преимуществами поддержки состояния марионетки.

Ответ 2

Оба ответа выше работают.
Вот еще один способ, который я предпочитаю использовать (чувствует больше backboney).

Привязать представление непосредственно к модели
Когда модель будет выбрана, заданная вами функция будет запущена. Это можно сделать с помощью моделей или коллекций.

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

Это также позволяет вам выбирать, когда захотите.

Ответ 3

на основе одного из примеров 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)     
  });

Ответ 4

Я возвращаюсь к той же проблеме и решил использовать систему событий Marionette, чтобы представления отображали их статус перед запуском show(). Я также использую requireJS, который добавляет некоторую дополнительную сложность - но этот шаблон помогает!

У меня будет один вид с элементом пользовательского интерфейса, который при щелчке вызовет событие для загрузки нового представления. Это может быть subview или navview - не имеет значения.

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

Это событие попадает в Wreqr setHandlers и запускает последовательность загрузки вида (в моем случае я делаю кучу логики для обработки переходов состояний). Последовательность "start" вводит новый вид и передает необходимые параметры.

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

Затем представление, получающее загрузку, обрабатывает коллекции/модели и выборку для инициализации. Вид прослушивает изменения модели/коллекции, а затем запускает новое "готовое" событие, используя команду wreqr executre.

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

У меня есть другой обработчик, который ловит это готовое событие (и параметры, включая ссылку на опцию представления), и запускает 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;

Я постараюсь написать приличный сундук всей системы и разместить здесь на следующей неделе или около того.