Often, controllers will need to access other controllers' properties and models. This is especially important when you have nested resources. In this recipe, we'll take a look at a nested controller that needs access to the parent controller's model and properties.
$ ember g route foo1 $ ember g route foo1/foo2 $ ember g controller foo1 $ ember g controller foo1/foo2 $ ember g template index
This generates the foo1
and foo2
routes and controllers. The foo2
route is a nested route. The index template will contain links.
router.js
file that all the routes have been created correctly:// app/router.js import Ember from 'ember'; import config from './config/environment'; const Router = Ember.Router.extend({ location: config.locationType }); Router.map(function() { this.route('foo1', function() { this.route('foo2'); }); }); export default Router;
As we generated the routes, router.js
should already be set up for us. As you can see, the foo2
route is nested under the foo1
route. What this means is that we'll have to access the URL at /foo1/foo2
to access the foo2
route.
// app/routes/foo1.js import Ember from 'ember'; export default Ember.Route.extend({ model(){ return ['abc','def','ghi']; } });
All this route does is return a model with a simple array of letters.
// app/routes/foo1/foo2.js import Ember from 'ember'; export default Ember.Route.extend({ model(){ return ['jkl','mno','pqr']; } });
The nested foo2
route also returns a simple array of letters in its model
hook.
// app/controlers/foo1.js import Ember from 'ember'; export default Ember.Controller.extend({ prop1: 'foo property' });
This controller has one string property.
foo1
model and properties:// app/controllers/foo1/foo2.js import Ember from 'ember'; export default Ember.Controller.extend({ foo1Controller:Ember.inject.controller('foo1'), foo1: Ember.computed.reads('foo1Controller.model') });
Ember.inject.controller
allows us access to the foo1
controller and properties. We can then use the Ember.computed.reads
method to set the foo1
property. This creates a read-only computed property that we can use in the template.
// app/templates/foo1.hbs <h3>Foo1</h3> {{#each model as |letters|}} {{letters}}<br> {{/each}} {{outlet}}
All the foo1
template does is display the list from the model.
// app/templates/foo1/foo2.hbs <h3>Foo2</h3> {{#each model as |letters|}} {{letters}}<br> {{/each}} <h3>Here is the model injected in from the foo1 controller</h3> {{#each foo1 as |letters|}} {{letters}}<br> {{/each}} <h3>Foo1 property</h3> {{foo1Controller.prop1}}
The foo2
template has access to all the properties of the foo2
and foo1
controllers. In this example, we can use the each
helper to list all the letters in the foo2
model. It can also use the foo1
computed property to list all the letters in the foo1
controller. We can even access individual properties using foo1Controller
.
// app/application.hbs {{#link-to 'application'}}<h2 id="title">Welcome to Ember</h2>{{/link-to}} {{outlet}}
The application file will have a link at the top:
// app/templates/index.hbs {{link-to 'Foo1 Route' 'foo1'}}<br> {{link-to 'Foo2 Route' 'foo1.foo2'}}
The link-to
helpers here link to the foo1
and foo2
routes.
The index home screen displays a link to each route.
As you can see, the foo1
template is displayed as well as the foo2
template. The
foo2
template has access to both the foo2
and foo1
properties and model.
Controllers can access other controllers using
Ember.inject.controller
. This is known as dependency injection. Dependency injection occurs when we take one object and inject it into another. Dependency injection is covered in more detail in the Using dependency injection recipe of Chapter 11, Real-Time Web Applications.