Managing dependencies between controllers

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.

How to do it...

  1. In a new application, generate a couple of new routes and templates:
    $ 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.

  2. Verify in the 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.

  3. Add a new model to the foo1 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.

  4. Add a new model to the foo2 route:
    // 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.

  5. Add a new property to the foo1 controller:
    // app/controlers/foo1.js
    import Ember from 'ember';
    
    export default Ember.Controller.extend({
        prop1: 'foo property'
    });

    This controller has one string property.

  6. Create a property in the foo2 controller that can access the 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.

  7. Update the foo1 template file:
    // 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.

  8. Update the foo2 template file:
    // 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.

  9. Add some basic links to the application and index template files:
    // 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.

  10. Start the Ember server and you'll see the following screen after you open a web browser:
    How to do it...

    The index home screen displays a link to each route.

  11. Click on Foo2 Route. The following window will be displayed:
    How to do it...

    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.

How it works...

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset