2013-08-07 2 views
4

У меня есть несколько различных моделей уровня приложения - то есть текущего пользователя, текущей учетной записи и т. Д. - которые я хочу загрузить перед рендерингом приложения. Как и где это должно быть сделано? This question/answer многое помогло, но не охватывает асинхронный аспект.Ожидание загрузки моделей перед рендерингом в Ember.js

Следующий код выполняет то, что я хочу, но загрузка моделей в beforeModel (чтобы воспользоваться этим ожиданием обещания решить) выглядит неправдой. Должен ли я загружать эти модели в ApplicationRoute?

App.ApplicationController = Ember.Controller.extend({ 
    currentAccount: null 
}); 

App.ApplicationRoute = Ember.Route.extend({ 
    beforeModel: function() { 
    var self = this; 

    return App.Account.find(...).then(function (account) { 
     self.controllerFor('application').set('currentAccount', account); 
    }); 
    } 
}); 

Благодарим за помощь!

ответ

6

Хитрость заключается в том, чтобы вернуть обещание от метода модели маршрута.
Это приведет к переходу маршрутизатора в маршрут App.LoadingRoute до тех пор, пока обезвреживание не будет разрешено (которое может быть использовано для загрузки индикационных баров/колес и т. Д.)
Когда обещание будет разрешено, приложение AppLoadingRoute будет деактивировано, а будет вызван метод установки исходного маршрута.
Это работает для обещаний с использованием данных ember, обещаний JQuery $ .ajax и обещаний по выбору ember-модели.
Просто убедитесь, что вы вернули фактическую модель после решения обещания.
Это также может быть хорошим местом для обработки ошибок, если обещание отклонено, но я оставлю это на какой-то другой вопрос.

Что касается того, где вы должны загружать свои модели - это зависит от использования вашего приложения.
Обычно вы загружаете модель, в которой URL указывает, что вам нужна эта модель. Правило большого пальца будет индикатором идентификатора модели в URL-адресе.
Это, конечно, меняется, если вам нужно предварительно выбрать некоторые данные.

А теперь для некоторого кода:

App.SomeRoute = Ember.Route.extend({ 
    model: function(params){ 
     return App.SomeModel.fetch(params.model_id).then(function(modelData){ 
      // it is better to return the actual model here, and not the promise itself 
      return App.SomeModel.find(params.model_id); 
     }); 

    }, 
    setupController: function(controller, model){ 
     controller.set("model", model); 
     // do some controller setup here - can be omitted if no setup is needed 
     // this will run only after the promise has been resolved. 
    } 
}); 

App.LoadingRoute = Ember.Route.extend({ 
     activate: function(){ 
      this._super(); 
      // add some loading indication here 
     }, 
     deactivate: function(){ 
      this._super(); 
      // remove loading indication 
     } 
} 

Надеется, что это помогает.

+0

Спасибо, но вы действительно не отвечаете, где я должен загружать модели уровня приложения, которые мне нужны во всем мире. Другими словами, модели, которые не зависят от URL. –

+1

, если они вам нужны, вы можете использовать метод init Ember.Application. –

+0

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

3

Мне удалось получить эту работу, используя вложенные Promises и метод afterModel в ApplicationRoute.

App.ApplicationRoute = Ember.Route.extend({ 

    model: function() { 

     // load the reservation (a globally needed model) 
     return App.Reservation.fetch().then(function(reservations) { 
      return reservations.get('firstObject'); 
     }); 

    }, 

    afterModel: function() { 

     // Load all other globally needed models 
     var self = this; 
     return App.Gender.fetch().then(function(genders) { 
      self.controllerFor('application').set('genders', genders); 
      return App.FilterAttribute.fetch().then(function(filterAttributes) { 
       self.controllerFor('application').set('filterAttributes', filterAttributes); 
       //return App.SomeOtherModel... 
      }); 
     }); 

    }, 

    setupController: function(controller, model) { 
     controller.set('reservation', model); 
    } 

}); 

Работает отлично :-) Приложение остается в LoadRoute, пока не будут загружены все записи. Обратите внимание, что я использую Ember Model, но это не имеет значения, просто нужно вернуть обещание.

6

Вы хотите предварительно загрузить данные/модели для инициализации приложения и почувствовать beforeModel неверно?

Похоже, вам нужен инициализатор приложения!

Ваш друг в этом случае:

App.deferReadiness(); // останавливать выполнение приложения до тех пор, пока все экземпляры этого вызова (то есть: несколько инициализаторов) не будут совпадать с экземпляром:

App.advanceReadiness(); // считаем, что это эквивалентно вызову разрешения обещания.

1) От вас смотрит пользователь непосредственно, изменение которых упоминается в соответствии с вашей установки приложения:

Ember.Application.initializer({ 
    name: 'loadUser', 
    after: 'store', 
    initialize: function(container, app) { 
     // modify this following to suit how you're determining the account 
     var url = 'user/' + currentAccount; 
     // tell the app to pause loading until advanceReadiness is declared 
     app.deferReadiness(); 

     // load from JSON 
     Ember.$.getJSON('url').then(function(json) { 

      var store = container.lookup('store:main'); 
      store.load(app.User, json); 

      // tell app to start progressing again 
      app.advanceReadiness(); 
     }); 
    } 
}); 

2) С помощью мета-тег:

Ember.Application.initializer({ 
    name: 'currentUser' 
    after: 'store', 

    initialize: function(container, app) { 
     app.deferReadiness(); 

     $(function() { 
      // Look up an attribute in a meta tag 
      var store  = container.lookup('store:main'), 
       attributes = $('meta[name="current-user"]').attr('content'); 

      if (attributes) { 
       var obj  = store.load(app.User, JSON.parse(attributes)), 
        user  = App.User.find(obj.id), 
        controller = container.lookup('controller:currentUser').set('content', user); 

       container.typeInjection('controller', 'currentUser', 'controller:currentUser'); 
      } 
      app.advanceReadiness(); 
     }); 
    } 
}); 

3) Через данные сеанса:

Ember.Application.initializer({ 
    name : 'currentUser', 
    after : 'session', 
    initialize: function(container, app) { 
     var controller = container.lookup('controller:currentUser'); 
     container.typeInjection('controller', 'currentUser', 'controller:currentUser'); 
    } 
});