从路由访问服务的承诺

Accessing a service's promise from a route

我正在努力获取路由中服务承诺的数据。当我在应用程序初始化时转换到路由时出现问题;也就是说,如果我加载应用程序,然后转换,一切都很好,因为承诺已经实现,但如果我在该路由上点击浏览器重新加载,违规行将不会 运行。服务是:

// services/lime-core.js
import Ember from 'ember';

export default Ember.Service.extend({
  store: Ember.inject.service(),
  resources: null,

  init() {
    this.set('resources', []);

    this.get('store').findAll('resource').then(resources => {
      this.set('resources', resources);
    });
  }
});

假设我已将该服务注入到组件中,该服务在模板中工作得很好。我按如下方式在路由中访问此服务:(假设 slug 具有有意义的值)

// dashboard/route.js
export default Ember.Route.extend({
  limeCore: Ember.service.inject(),
  ...
  model(params) {
    ...
    this.set('resource', this.get('limeCore.resources').findBy('slug', slug));
    ...
  }
}

model() 钩子被调用时,limeCore 服务的 init() 方法仍在等待 Promise 完成。我试图变得聪明,但将代码更改为:

this.get('limeCore.resources').then(resources => {
  this.set('resource', resources.findBy('slug', slug))
});

不起作用,因为 this.get('limeCore.resources') 不是 return Promise。这个逻辑必须在路由中(即不能移动到模板),因为我依赖于 slug 值来确定一个 ID,它加载了一组不同的 ember-data.

同样,一旦 Promise 已经实现,这段代码就可以正常工作——也就是说,在未来过渡到这条路线时,但不是在初始应用程序加载时。

我确信有一个正确的方法来做到这一点...服务需要 return 一个承诺(同时仍然可以在模板中使用),或者我需要确保承诺在可以执行 Route.model() 方法之前完成。

谢谢!

我会使用的方法

app/misc/lime_core.js

function getResources(store) {
     return store.findAll('resource')
}

export { getResources };

随机路线

import { getResources } from 'app/misc/lime_core';

export default Ember.Route.extend({
   model: function() {
     const store = this.get('store');
     const sourcePromise = getResources(store);
   }     
})

但如果您仍在寻找服务方式,我会像这样使用它

export default Ember.Service.extend({
  resources: null,
  store: Ember.inject.service(),


  getResources: function() {
     return this.get('store').findAll('source')
  }
});

路线

    limeCore: Ember.inject.service(),

    model: function() {
       const store = this.get('store');
       const sourcePromise = this.get('limeCore').getResources(); // sourcePromise.then(...

    } 

" 我的路由的 model() 方法结果取决于资源的 id"

    model: function() {
       this.get('limeCore').getResources().then(sources => {
          return Ember.RSVP.hash({
               artifact: store.find('artifact', { source: source.get('firstObject.id)})
          })
       })
   }

或方案二

     model: function() {
           return Ember.RSVP.hash({
                   artifact: this.get('limeCore').getResources().then(sources => {
                       return store.find('artifact', {source: xx}) 
                  })
              })
           })
       }

您的 getResources 函数也可以根据您的条件进行修改

function getResources(store) {
         return store.findAll('resource').then(r => r.findBy('id', 1))
}

我认为我的问题措辞不当,因此我向 reader 道歉。发生这种情况是因为如果我正要问问题,通常是因为我无法表达问题。

上面建议的方法对我不起作用,尽管它提供了一些有用的提示。重要的要求是(正如我在评论中提到的)我需要在模型查询中使用 resource.id 值。 kristjan 的方法解决了这个问题,但我的问题没有充分说明 model() 方法有多复杂。

第二个不成文的要求是 ajax 请求只发出一次,因为数据很少更改并且在应用程序负载的很多地方都需要。

最后,我能够混合使用 kristjan 的方法——创建一个 limeCore.getResource() 方法,将数据加载到 Promise 中,然后在我的路由 beforeModel() 钩。我意识到的关键是 beforeModel()model() 一样,会等到 Promise 解析后才调用下一个钩子。在我的应用程序中,model() 永远不会 运行 直到这些核心对象被加载(model() 依赖于它们),所以在之前加载它们是有意义的。也许有更优雅的方法(我愿意听),但至此我觉得问题已经解决了!

// services/lime-core.js
import Ember from 'ember';

export default Ember.Service.extend({
  store: Ember.inject.service(),
  resources: null,
  clients: null,

  init() {
    this.set('resources', []);
    this.set('clients', []);
  },

  // getCoreObjects() needs to be called at least once before the resources, clients and projects are available in the application. Ideally this method will be called in the route's beforeModel() hook. It cannot be called from the application route's beforeModel() hook because the code will not succeed if the user isn't authenticated.
  getCoreObjects() {
    if (this.get('resources').length === 0 || this.get('clients').length === 0) {
      return Ember.RSVP.hash({
        resources: this.get('store').findAll('resource').then(resources => {
          this.set('resources', resources);
        }),
        clients: this.get('store').findAll('client', {include: 'projects'}).then(clients => {
          this.set('clients', clients);
        })
      });
    } else {
      return Ember.RSVP.hash({});
    }
  }
});

在我的路线中:

// routes/dashboard.js
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';

export default Ember.Route.extend(AuthenticatedRouteMixin, {
  limeCore: Ember.inject.service(),
  session: Ember.inject.service(),
  ...
  beforeModel(transition) {
    this._super(...arguments);
    if (this.get('session.isAuthenticated')) {
      return this.get('limeCore').getCoreObjects();
    }
  },

  model(params) {
    ...
    this.set('resource', this.store.peekAll('resource').findBy('slug', slug));
    ...
    return this.store.query('artifact', {'resource-id': this.get('resource.id')});
  }
}