1
votes

I am currently loading some ember-data which is used site-wide from the routes/application.js route. That data can then be accessed anywhere. In particular, the data is passed to a component from the templates/application.hbs template, and it's store.peekAll() accessed from a variety of other places.

Whether this is the right approach or not (and I welcome feedback on that!), this works for me, EXCEPT in the following case:

If the user is not authenticated, I can't query for the data, because they are not yet authorized to view it. This is the code I have:

// routes/application.js
import Ember from 'ember';

export default Ember.Route.extend(ApplicationRouteMixin, {
  model() {
    if (this.get('session.isAuthenticated')) {
      return Ember.RSVP.hash({
        clients: this.store.findAll('client', {include: 'projects'}),
        resources: this.store.findAll('resource')
      });
    }
  }
});

I would like to make the data load after they authenticate, but I don't know how to make the model re-load. If I just have the data load in the sessionAuthenticated hook, as follows:

// routes/application.js
sessionAuthenticated() {
  this.controller.set('clients', this.store.findAll('client', {include: 'projects'}));
  this._super(...arguments);
}

It doesn't work. The store gets filled with the data, but the components that depend on this data never see it. Also, the route that I transition to next, which also depends on the data, doesn't have it in time because of synchronicity.

There must be a simple way to do this, but I'm baffled as to what it is. Observers? Forcing the routes/application.js model() method to re-run (and wait until the promise returns) now that session.isAuthenticated is true?

ember: 2.5.x, ember-data: 2.5.x

2
As you already know, the problem is you are doing this on the application route. Have you considered providing these models from a service? Inject the service into the routes that need access to clients/resources.Paul Oliver
That sounds like the right approach. I won't be able to try until next week, but I'll report back here!pauldoerwald
This approach was mostly successful; I posted a follow-on question that I hope will answer the rest of the way. In the meantime, I will answer this question below with what I came up with.pauldoerwald

2 Answers

1
votes

I implemented the service as follows:

// 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', []);

    this.get('store').findAll('resource').then(resources => {
      this.set('resources', resources);
    });
    this.get('store').findAll('client', {include: 'projects'}).then(clients => {
      this.set('clients', clients);
    });
  }
});

I was then able to access the limeCore service in templates, provided it was injected:

// components/foo/component.js
export Ember.Component.extend({
  limeCore: Ember.Service.inject(),
  ...
}

and my template:

// components/foo/template.hbs
<ul>
  {{#each limeCore.resources as |resource|}}
    <li>{{resource.name}}</li>
  {{/each}}
</ul>
0
votes

Try this:

// routes/application.js
import Ember from 'ember';

export default Ember.Route.extend(ApplicationRouteMixin, {
  model() {
    if (this.get('session.isAuthenticated')) {
      return Ember.RSVP.hash({
        clients: this.store.findAll('client', {include: 'projects'}),
        resources: this.store.findAll('resource')
      });
    }
    return {};
  },
  sessionAuthenticated() {
    this.store.findAll('client', {include: 'projects'}).then(clients => {
      this.controller.set('model.clients', clients);
    });

    this._super(...arguments);
  }
});