Last reviewed in September 2016 with Ember 2.8 Update to Ember Octane in progress!

At this point, you already asked yourself if your component should load data.

If so, how do you render UI while waiting for a promise to resolve? Should you place a conditional in the template? Fetching data from the server inside the component is good practice?

Let's have a look.

full-featured article about rendering promise-backed computed properties: The Guide to Promises in Computed Properties Ember Igniter has now a

Data-thirsty Dropdown Menu

In the app's navigation bar, we have a component that suggests cities you may like. It doesn't make sense to load this in a route, as this concern has a longer life than (and is independent of) the route.

It isn't architecturally sound for the component to make an ajax call. That's what we'll use a Service for:

// app/services/geo.js export default Ember . Service . extend ( { cities ( ) { // this simulates fetching data across the network return new Ember . RSVP . Promise ( function ( resolve ) { Ember . run . later ( function ( ) { resolve ( [ "Paris" , "Washington DC" , "Bogota" , "Nairobi" , "Auckland" ] ) ; } , 3000 ) ; } ) ; } } ) ;

We'll inject this service in our bare-bones drop-down component:

// app/components/drop-down.js export default Ember . Component . extend ( { geo : Ember . inject . service ( ) , cities : null , didInsertElement ( ) { this . _super ( ... arguments ) ; this . get ( 'geo' ) . cities ( ) . then ( ( cities ) => { this . set ( 'cities' , cities ) ; } ) ; } } ) ;

If you were to load from Ember Data, inject the store Service. Remember all store calls already return promises!

// app/components/drop-down.js export default Ember . Component . extend ( { store : Ember . inject . service ( ) , cities : null , didInsertElement ( ) { this . _super ( ... arguments ) ; this . get ( 'store' ) . findAll ( 'city' ) . then ( ( cities ) => { this . set ( 'cities' , cities ) ; } ) ; } } ) ;

And

{{! app/templates/components/drop-down.hbs }} {{#if cities}} < select > {{#each cities as |city|}} < option > {{ city }} < / option > {{/each}} < / select > {{ else }} Loading... {{/if}}

That's right: the component will call the cities method of the Service, which returns a promise.

It will do that on didInsertElement (i.e. when the component is available in the DOM) or upon any other component lifecycle hook. When the promise resolves, it will populate the cities property – and the template reacts to this accordingly.

Sure, we haven't handled errors and there are variations of the problem. But this should give you this gist of how to approach it!

Much more in the guide to Promises in Computed Properties.