A big part of the benefit of Ember is that an experienced Ember developer can quickly get up to speed and contribute to an existing project. So, there is most certainly a benefit in exercises that involve cloning an existing project and modifying them. This also permits us to avoid a bunch of setup commands and redundant work at the start of the episode. So today, we are going to clone a
School Directory Project
and add some features. In this project we once again have a
contact
model with some attributes, a
contacts
and
contacts/contact
route. We are also using
Ember CLI Mirage
to provide our development data and our fake 'API server'. Finally, we are using
Bootstrap 4
for our css framework. Anyway, enough with the preliminaries, let's get going.
$ git clone https://github.com/baroquon/school-directory
$ cd school-directory
$ git checkout starting-point
$ npm install && bower install
$ ember s
[Visit localhost:4200](http://localhost:4200)
If we visit the contacts route you will notice that we have mixture of students and faculty in our list. We are using the same
contact-card
component to display their information. However, what if we want to see some information that is specific to a teacher or student? Say for students we want a list of their current courses and for teachers we want to see their education background. There are several ways to accomplish this. First let's generate our two components.
$ ember g component past-education && ember g component current-courses
First we'll open the
current-courses
template and modify it to look like we want:
In
app/templates/components/current-courses.hbs
: We'll pass in the contact so let's iterate over the contact's currentCourses and list the title, creditHours, and description. Adding this class so that Bootstrap will make it look pretty.
{{#each contact.currentCourses as |course|}}
<li class='list-group-item'>
<h4>{{course.title}}</h4>
<p>Hours: {{course.creditHours}}</p>
<p>{{course.description}}</p>
</li>
{{/each}}
Now, in the component's JavaScript we'll just add a tagName and some class names.
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'ul',
classNames: ['list-group', 'list-group-flush']
});
Do basically the same thing for the teacher's component. In
app/components/past-education.js
we'll make it look the same as current-courses:
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'ul',
classNames: ['list-group', 'list-group-flush']
});
In the template, it will be similar, but we'll iterate over the contact's
pastExperiences
property and include that model's properties.
{{#each contact.pastExperiences as |experience|}}
<li class='list-group-item'>
<h4>{{experience.school}}</h4>
<p>{{experience.degree}} - {{experience.major}}</p>
<p>Minor: {{experience.minor}}</p>
</li>
{{/each}}
Now let's open our contact-card template and add these new components. In
app/templates/components/contact-card.hbs
.
<div class="card-image-container">
<img src="{{contact.avatar}}" class="card-img-top" alt="Card image cap">
</div>
<div class="card-block">
<h4 class="card-title">{{contact.fullName}}</h4>
<p class="card-text">{{contact.role}}</p>
<p class="card-text"> <strong>phone:</strong> {{contact.phone}}</p>
<p class="card-text"><strong>email:</strong> <a href="mailTo={{contact.email}}" class="card-link">{{contact.email}}</a> </p>
</div>
If we are going to display a different component depending on if our contact is a teacher or student we could use a simple conditional and just each component.
{{#if isTeacher}}
{{past-education contact=contact}}
{{else}}
{{current-courses contact=contact}}
{{/if}}
But, we don't need to. We can use Ember's component helper to get the correct component rendered.
{{component additionalInfo contact=contact}}
Now, we just need to create an 'additionalInfo' computed property that returns the name of the component we want to render as a string.
To accomplish this, open
app/components/contact-card.js
and add a computed property called
import Ember from 'ember';
export default Ember.Component.extend({
classNames: 'card',
additionalInfo: Ember.computed('contact.isTeacher', function(){
if(this.get('contact.isTeacher')){
return 'past-education';
} else {
return 'current-courses';
}
})
});
We have a computed property on the contact model called
isTeacher
that just returns true or false depending on the person's
role
.
That does it for now. We were able to get an existing Ember application up and running and we used the component helper to deal with branching UI needs based on data. We are going to continue iterating on this application for a while moving forward. In real life, we don't create a simple application and move on to other things, we spend most of our time iterating on existing applications. So, we will try and do some of that with this app.
Tomorrow we will look at building our application for production. The we will add pagination to our contacts list. See you then.
Notes
There are a few addons that allow you to easily integrate Bootstrap with your Ember CLI project. For this repo I tried both bennycwong/ember-bootstrap-4 and kaermorchen/ember-cli-bootstrap-4 and they were both perfectly fine. If you want to use Bootstrap 3 for a project you should check out ef4/ember-sass-bootstrap . It is also worth nothing that all of these depend on you having SASS available - see aexmachina/ember-cli-sass .
Comments for Extending an Existing Application - Using the Component helper