This week we are going to take a bit more in depth look at Ember routes and components. There won't be a lot of implementation this week; it will mostly be overview. The following week we will put these principles into action by building some Ember apps. Today we'll see a solution to the previous exercise, as well as a few resources to help prepare you for the upcoming drips.

Solution

In the last drip you were tasked with creating a contacts.show route for our contacts-management application that we created. There are a couple of ways to go about this. You can either manually create and modify the files, or use the generators. For our purposes, let's do the work by hand.

First, we need to modify our router by adding the show route with a dynamic segment for the id.

import Ember from 'ember';
import config from './config/environment';

const Router = Ember.Router.extend({
  location: config.locationType
});

Router.map(function() {
  this.route('contacts', function() {
    this.route('show', { path: ':contact_id' });
  });
});

export default Router;

Then we need to create the route in app/routes/contacts/show.js:

import Ember from 'ember';

export default Ember.Route.extend({
  model(params){
    return this.store.findRecord('contact', params.contact_id);
  }
});

We will need to create a template in app/templates/contacts/show.hbs. I made mine look like this:

<div>
  <h2>
    {{model.firstName}}
    {{model.lastName}}
  </h2>
  <h3>
    {{model.email}} | {{model.phone}}
  </h3>
  <br>
</div>
{{#each model.addresses as |address|}}
  <div>
    {{address.street1}}
    {{address.street2}}
    <br>
    {{address.city}}, {{address.state}} {{address.zip}}
  </div>
  <br>
{{/each}}

Ideally, we would have created components for displaying the contact. But for the sake of simplicity we will avoid that for now. Now that we have that created, we should make our address model. In app/models/address.js:

import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo } from 'ember-data/relationships';
// import { hasMany } from 'ember-data/relationships';

export default Model.extend({
  street1: attr('string'),
  street2: attr('string'),
  city: attr('string'),
  state: attr('string'),
  zip: attr('string'),
  contact: belongsTo('contact')
});

We also need to add the relationship to out contact model:

import { hasMany } from 'ember-data/relationships';
// ...
addresses: hasMany('address')

Now, that we have all of that out of the way, we can link to our new route in our old template. In app/templates/contacts.hbs:

<nav class='contacts'>
  {{#each model as |contact|}}
    {{#link-to 'contacts.show' contact.id}}{{contact.firstName}} {{contact.lastName}}{{/link-to}}
  {{/each}}
</nav>
{{outlet}}

Again, if you were building an application for production, you would definitely want to employ more components and use the controller/template as just a passthrough for the model. At any rate, that about does it for this exercise.

Preparatory Readings

This week we are going to focus on diving a little deeper with Routes and Components. The most useful resource for understanding Ember is the Docs and the code. With that in mind, here are some links to Ember's Guide and API Docs.