Example of using ember-data in a service


#1

I need to create a service that does data retrieval as it is data that will be used across mutliple routes (user-profile data).

I have a service created, and I have the ember-data store injected into it, but calls to the service from my components don’t seem to trigger the data retrieval? I find lots of people alluding to this approach, but no examples of how it’s done.

Does anyone have an example of a service being used to consume data from ember-data and make it accessible via a component?

I know routable components coming at some point makes this better, but I don’t have any dates on when that is coming, and I need this functionality quickly.


#2

This definitely works (at least from v. 1.13 up), we use it in several places. Without seeing your code it is hard to tell what went wrong, though. Here are a couple of suggestions:

  • Did you actually inject the store into the service? Afaik the store is not auto-injected. Did you also inject the service into your component?
  • You can put in “debugger” statements in your JS code and the execution will stop at that point if you have the dev tools open. Try that in order to figure out what went wrong.
  • Methods on the store usually return promises. Maybe you’re not waiting for them to resolve?

Maybe you can also try to set up an example of what you’re trying to do on an Ember Twiddle.

This is a simplified example of something that we use in a project right now:

// app/services/landing-page-model.js
export default Ember.Service.extend({
  store: Ember.inject.service(),

  lookupModel(slug) {
    return this.get('store').query('vendor', { vendor_slug: slug });
  }
});

// app/routes/landing-page.js
export default Ember.Route.extend({
  modelService: Ember.inject.service('landing-page-model'),

  model(params) {
    return this.get('modelService').lookupModel(params.slug);
  }
}

this uses a route but the principle should be the same for a component.


#3

I don’t know what to tell you, but that same code doesn’t work for me. I don’t see the call to the API ever getting invoked.

Component Code:

import Ember from 'ember';
    export default Ember.Component.extend({
    userProfile: Ember.inject.service('user-profile'),

    profile() {
         return this.get('userProfile').getProfile();
    }
});

Service Code

import Ember from 'ember';
import DS from 'ember-data';

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

     getProfile() {
         return this.get('store').findRecord('user', 1234 );
    }
});

I know the inject call on the store in the Service layer is redundant (meaning I don’t need to define the ‘store’ in the .service() call, but it didn’t work without it either.


#4

Did you try putting in a debugger statement to see where the problem lies?


#5

I did, using the debuggger in the browser (as I can’t find documentation on how to debug Ember any other way in 2.2).

What I am finding is that the components method seems to be invoked, but it’s contents aren’t ever invoked. So the call to the service isn’t getting made, or maybe I just can’t read the damn debugger.


#6

So you get into the profile() method of your component but not into the getProfile() of your service?

You can just drop a debugger statement anywhere in your JS source code and the browser will set a breakpoint as long as the dev tools are open.


#7

In doing more research, the profile() method on my component never gets executed. In part becuase I really need profile to be a property not a function. At least if I turn it into a property and put static text behind it, then I at least start getting a response.

So if the component code was

profile: {firstName: "Josh" }

Then the template can show it without issue, but if I change it to the function call, it breaks.

I am trying to use this as a way to do a async load of data, so I want the template to call profile.firstName and display text. That doesn’t seem to work when the profile object in the component is a function.


#8

Oh I see the problem. I thought your code was part of a larger class. Yes, you cannot “directly” execute methods on a component from a template. You can either send an action to it or use a property (computed or not).

In this case it depends on what you want to accomplish. The usual way would be to load the user profile in the route that contains the component. You could either do this in the ApplicationRoute if you decide you need it everywhere or you could create a BaseRoute class that loads the profile and that all routes that need it inherit from; another possibility is to use a Mixin or to use the service the way you wanted and call it explicitly from every route that needs it; this keeps things somewhat more decoupled and explicit.