从路线访问服务的承诺 [英] Accessing a service's promise from a route

查看:119
本文介绍了从路线访问服务的承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力服务于路线中承诺的数据。当我在应用程序init转换到Route时,会发生此问题;也就是说,如果我加载应用程序,然后转换,一切都很好,因为承诺已经实现了,但是如果我在该路由器上浏览器重新加载,那么违规行将不会运行。该服务是:

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

导出默认值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 具有有意义的值)

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

模型() hook被调用, limeCore 服务的 init()方法仍在等待承诺要实现,我试图变得聪明,但是将代码更改为:

  this.get('limeCore。资源')然后(资源=> {
this.set('resource',resources.findBy('slug',slug))
});

不起作用,因为 this.get('limeCore.resources')不返回承诺,这个逻辑必须在路线上(即不可能)移动到一个模板),因为我依赖于slug值来确定加载一组不同的ember数据的ID。



同样,这段代码正常工作一旦承诺已经实现 - 也就是说,在未来向此路线过渡,但不是初始应用程序加载。



我确定有一个正确的方法这样做...或者服务需要返回承诺(同时仍然可以在模板中使用),或者我需要确保Promise在 Route.model()方法可以执行。



谢谢!

解决方案

我认为我的问题措辞不好,所以我向读者道歉。这是因为如果我提出一个问题,那通常是因为我无法表达问题。



上面提出的方法没有办法对我来说,虽然它提供了一些有用的提示。重要的要求是(正如我在评论中提到的),我需要在模型查询中使用 resource.id 值。 kristjan的方法解决了,但我的问题并没有充分显示出model()方法的复杂程度。



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



最后,我能够使用kristjan的方法 - 创建一个在Promise中加载数据的limeCore.getResource()方法,然后在路由的 beforeModel()钩子中要求承诺。我意识到的关键是, beforeModel(),如 model(),将等到Promise在调用前解决下一个钩子。在我的应用程序中, model()永远不会运行,直到这些核心对象被加载( model()取决于他们),所以有理由让他们之前加载。也许有一个更优雅的方法(我可以听到),但在这一点上,我觉得问题已经解决了!

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

导出默认值Ember.Service.extend({
store:Ember.inject.service(),
resources:null,
clients:null,

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

// getCoreObjects()需要在资源,客户端和项目在应用程序中可用之前至少调用一次。理想情况下,该方法将在路由的beforeModel()钩子中调用,不能从应用程序路由的beforeModel()钩子,因为如果用户未通过身份验证,代码将不会成功。
getCoreObjects(){
if(this.get('resources')。length === 0 || this.get('clients')。length === 0){
return Ember.RSVP.hash({
resources:this.get('store')。findAll('resource')。然后(资源=> {
this.set('resources',resources);
}),
客户端:this.get('store')。findAll('client' {include:'proj ects'})然后(clients => {
this.set('clients',clients);
})
});
} else {
return Ember.RSVP.hash({});
}
}
});

在我的路线:

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

导出默认值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')});
}
}


I am struggling to a Service's promised data in a Route. The problem occurs when I am transitioning to the Route at application init; that is, if I load the application, then transition, everything is fine, because the promise is already fulfilled, but if I hit browser reload on that Route, the offending lines won't run. The Service is:

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

This service works perfectly in a template, assuming I have injected the service into the component. I access this service in the route as follows: (assume slug has a meaningful value)

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

When the model() hook is called, the limeCore service's init() method is still waiting for the Promise to fulfill. I tried to be clever, but changing the code to something like:

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

doesn't work, because this.get('limeCore.resources') does not return a Promise. This logic has to be in the route (i.e. can't be moved to a template), because I'm dependent on the slug value to determine an ID which loads a different set of ember-data.

Again, this code works properly once the Promise has been fulfilled — that is, on a future transition to this route, but not on initial application load.

I'm sure there is a correct way to do this... either the Service needs to return a Promise (while still being usable in templates), or I need to make sure that the Promise is fulfilled before the Route.model() method can be executed.

Thanks!

解决方案

I think my question was poorly phrased, so I apologize to the reader for that. This happened because if I'm at the point of asking a question, it's often because I'm having trouble expressing the problem.

The approach suggested above didn't work for me, although it gave a few helpful hints. The significant requirement was that (as I mentioned in the comment) I needed to use the resource.id value in the model query. kristjan's approach addressed that, but my question didn't sufficiently show how complicated the model() method was.

An unwritten second requirement was that the ajax request is only made once, because the data rarely changes and is required in a lot of places on application load.

In the end, I was able to use a blend of kristjan's approach — creating a limeCore.getResource() method that loads the data in a Promise, and then require that promise in my route's beforeModel() hook. The key thing I realized was that beforeModel(), like model(), will wait until a Promise resolves before calling the next hook. In my application, model() should never run until these core objects have been loaded (model() is dependent upon them), so it made sense to have them loaded before. Perhaps there is a more elegant approach (which I'm open to hearing), but at this point I feel the issue has been resolved!

// 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({});
    }
  }
});

and in my route:

// 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')});
  }
}

这篇关于从路线访问服务的承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆