Как предотвратить отображение 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 автоматически отображает представление.
Также смотрите:
Магическая сетка Макросъемка Отображение перед завершением выборки
Ответы
Ответ 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;
Я постараюсь написать приличный сундук всей системы и разместить здесь на следующей неделе или около того.