Магистральные маршрутизаторы: дождаться получения данных сначала
Я думаю, что я не совсем понимаю, как правильно использовать маршрутизаторы Backbone. Вот что я получил:
У меня есть некоторые данные, которые я извлекаю с сервера, когда страница загружается, а затем упаковывает ее в модели и коллекции. Количество этих моделей и коллекций является неопределенным. Я хочу использовать маршрутизатор, чтобы иметь возможность отображать представление определенных коллекций непосредственно с самого начала.
Проблема заключается в следующем: базовый маршрутизатор запускается раньше, и поскольку я прошу его получить доступ к определенному виду и вызвать его действие render
, он не сможет этого сделать, потому что эти представления еще не созданы. Это означает, что мне действительно нужно запустить мои маршруты после завершения выборки.
Я не знаю, подходит ли это для этого, но единственная идея, которую я придумал, заключается в следующем:
- Оберните определение маршрутов и бит
Backbone.history.start();
в отдельную функцию, доступную на верхнем уровне (например, подготовьтесь к ее вызову вручную позже).
- Запустите эту функцию как обратный вызов
success
для моих коллекций fetch()
- Количество этих коллекций неизвестно, также я не могу узнать, когда все они были извлечены, и я не хочу запускать маршруты более одного раза. Поэтому я использую
_.defer()
и _.once()
.
Это работает, но это выглядит очень странно:
Маршрутизаторы:
window.startRoutes = _.once(function() {
var AccountPage = Backbone.Router.extend({
routes: {
'set/:id': 'renderSet',
},
renderSet: function(setId) {
/** … **/
// Call the rendering method on the respective CardView
CardsViews[setId].render();
}
});
var AccountPageRouter = new AccountPage;
Backbone.history.start();
});
Коллекция:
window.CardsCollection = Backbone.Collection.extend({
model: Card,
initialize: function(params) {
/** … **/
// Get the initial data
this.fetch({success: function() {
_.defer(startRoutes);
}});
},
});
Итак, мой вопрос... я все правильно? Или есть лучший способ сделать это (должно быть)?
Ответы
Ответ 1
Вы можете определить свой маршрутизатор раньше времени; он ничего не сделает, пока не назовете Backbone.History.start().
Вы можете связать событие "reset" в своей коллекции, чтобы начать историю следующим образом:
my_collection.bind("reset", _.once(Backbone.History.start, Backbone.History))
Затем маршрутизатор начнет делать вещи, когда ваша коллекция будет полностью загружена. Я не уверен, что это именно то, что вы ищете (поскольку вы упомянули о наличии переменного количества коллекций).
У меня есть аналогичная ситуация, за исключением того, что я заранее знаю, какие коллекции я хочу загрузить до начала маршрутизации. Я добавил метод startAfter для своего маршрутизатора, например:
window.Workspace = new (Backbone.Router.extend({
. . .
startAfter: function(collections) {
// Start history when required collections are loaded
var start = _.after(collections.length, _.once(function(){
Backbone.history.start()
}))
_.each(collections, function(collection) {
collection.bind('reset', start, Backbone.history)
});
}
}));
а затем после того, как я установил свои коллекции
Workspace.startAfter([collection_a, collection_b, ...])
Это может быть адаптировано для работы с автономными моделями, хотя я думаю, что вам нужно привязать к чему-то другому, кроме события reset.
Я рад, что прочитал ваш пример кода, использование _.once и _.defer указало мне в правильном направлении.
Ответ 2
Я просто проверяю мой метод .render()
, чтобы все необходимые поля заполнялись, прежде чем использовать его. Если он еще не заполнен - я создаю виджет "Загрузка...".
И все мои взгляды подписаны на изменения модели, this.model.bind('change', this.render, this);
, поэтому сразу после загрузки модели снова будет вызываться render()
.