New to Ember? Part 1: Get Started

If there were a framework competition on Hello world apps, Ember would lose hands down.

For any substantial, complex, real-world application, Ember is bliss.


We need to start small in order to learn Ember, and that’s exactly what we’ll do today. We will build a TO-DO widget app, which is not the simplest Ember app ever but will show you a good deal of its foundations.

Ember’s strongest point is its philosophy, as reflected by phrases on the official website: “don’t waste time making trivial choices”, “don’t reinvent the wheel” and “built for productivity” (not for hype!)

Ember CLI in a nutshell

Ember CLI stands for Ember Command Line Interface. It’s an essential tool for a productive development experience and, as such, the starting point of any new app. It shares common idioms and Ember’s philosophy of not reinventing the wheel.

Based on Broccoli, npm and Bower, it offers template/asset compilation, dependency management and a vibrant add-on ecosystem.

Among other features:

Most importantly, it enforces a strong conventional project structure.

Getting up and running

In order to install Ember CLI we need node.js and npm.

You can easily get a binary from the node.js website if you haven’t got npm running on your machine.

For Mac OS X users who have Homebrew the installation process is even easier:

$ brew install node

Then check if npm is available:

$ npm -v
2.10.1

Installing Ember CLI is straightforward:

$ npm install -g ember-cli

Or, for a specific version, like 2.2.0-beta.6, use:

$ npm install -g ember-cli@2.2.0-beta.6

Done?

Finally, we ensure the ember command is ready to use:

$ ember -v
version: 2.2.0-beta.6
node: 0.12.4
npm: 2.14.10
os: darwin x64

All set!

Once we need it, here’s how to update Ember, Ember Data or Ember CLI (I bookmarked the page!).

TO-DO widget app

Let’s go ahead and create it:

$ ember new todo-app
version: 2.2.0-beta.6
installing app
  create .bowerrc
  create .editorconfig
  create .ember-cli
  # ...
Successfully initialized git.
Installed packages for tooling via npm.
Installed browser packages via Bower.

(Is ember new taking forever? Try this.)

Let Ember CLI serve our app and open our browser at localhost:4200

$ cd todo-app
$ ember server
version: 2.2.0-beta.6
Livereload server on http://localhost:49152
Serving on http://localhost:4200/

And that’s a beautiful start!

This is the anatomy of our brand-new Ember app:

As we saw before, Ember CLI enforces a well-defined structure for our apps. The official guide has a detailed explanation of all these files and directories.

This tutorial will give you quick and practical knowledge.

If you’d like to dive deeper and grasp these concepts (routes, components, models, etc) before putting them into practice, I recommend pausing here and reading 5 Essential Ember 2.0 Concepts You Must Understand.

Our goal here is to have a page with an input box, through which we can add TO-DOs.

Finished app

First thing, we’ll generate a route:

$ ember generate route todos
version: 2.2.0-beta.6
installing route
  create app/routes/todos.js
  create app/templates/todos.hbs
updating router
  add route todos
installing route-test
  create tests/unit/routes/todos-test.js

This particular blueprint got us the route, its associated template and a routing declaration in the Router. As well as the corresponding testing files. Next, we’ll see what’s what.

Ember articles like this delivered straight to your inbox? Tell me where:

(A few e-mails per month. No BS. Unsubscribe anytime!)

  1. It added a route (/todos) in the Router:

    Ember is URL-driven. Everything starts at the URL.

    // app/router.js
    
    // ...
    
    Router.map(function() {
      this.route('todos');
    });
        
    
  2. It created the route file at app/routes/todos.js (which will be invoked when /todos is visited)

    Routes are used to load models based on information from the URL.

    They also handle actions related to loaded models or to URLs (such as transitions).

  3. It created the template at app/templates/todos.hbs

    Templates are used to display model data in HTML (using the templating language HTMLBars). They receive the model loaded in the route as a parameter.

    We will use this top-level template exclusively to include components, which are reusable pieces of presentation and behavior. In this case, our TO-DO widget.

  4. We will now create the actual todo-widget:

    $ ember generate component todo-widget
    version: 2.2.0-beta.6
    installing component
      create app/components/todo-widget.js
      create app/templates/components/todo-widget.hbs
    installing component-test
      create tests/integration/components/todo-widget-test.js
        
    

Putting things to work

Let’s follow the path down, from URL to HTML, step by step.

Rough diagram of the flow from URL to HTML

  1. Router: Visiting localhost:4200/todos will only show “Welcome to Ember”. We’ve got work to do.

  2. Route: Probably the most important function in our routes is called model(). Let’s return data for our template to use.

    // app/routes/todos.js
    
    import Ember from 'ember';
    
    export default Ember.Route.extend({
    
      model() {
        return [
          { text: "Create Ember app" },
          { text: "Read Ember Igniter" },
          { text: "Master Ember" }
        ]
      }
    
    });
        
    

    These are our three models (default TO-DO items).

    Important note about models. Models can be represented by different data structures. For the sake of this example, we return a hard-coded array of plain-old Javascript objects.

    In real-world applications, though, we want to return the freshest data (whether stored in a local or a remote database behind an API). Ember Data exists for this very reason. Tell-tale signs of its usage are:

    • Loading data in routes via this.store.findAll() or this.store.findRecord()
    • Model classes extending DS.Model placed in the app/models directory

    To keep things simple, this guide won’t cover Ember Data. Here are a few in-depth articles that do:

    My recommendation is to read those after finishing this tutorial.

  3. Template: Receives the model parameter from the route. That is an array of Todos, so we’ll assign that data to the todos property of the todo-widget component:

    {{! app/templates/todos.hbs }}
    
    {{todo-widget todos=model}}
        
    

    (Later, we will see what {{outlet}} means. For now, we can remove it.)

    We may reuse this widget across our application with that single line of code.

  4. Component. It received an array of Todos, so we will use the each helper to iterate over it.

    {{! app/templates/components/todo-widget.hbs }}
    
    <ul>
    {{#each todos as |todo|}}
      <li>{{ todo.text }}</li>
    {{/each}}
    </ul>
        
    

Result:

To enable adding items, we will create an add-todo component.

$ ember generate component add-todo

We will make use of the input helper, which binds the current value to the component’s property text.

{{! app/templates/components/add-todo.hbs }}

<form {{action "submit" on="submit"}}>
  {{input value=text}} <button type="submit">OK</button>
</form>

When the form is submitted, we trigger an action called submit, defined on the component’s Javascript file:

// app/components/add-todo.js

import Ember from 'ember';

export default Ember.Component.extend({

  actions: {
    submit() {
      const text = this.get('text');
      this.get('onAdd')(text);
    }
  }

});

this.get() is Ember’s way of getting a property.

onAdd is one such property: a closure action. Our todo-widget component now calls the add-todo component like this, passing in the function:

{{! app/templates/components/todo-widget.hbs }}

{{add-todo onAdd=(action 'addTodo')}}

<ul>
{{#each todos as |todo|}}
  <li>{{ todo.text }}</li>
{{/each}}
</ul>

Whenever we submit the form in the add-todo, the function addTodo in todo-widget will be invoked.

In short, we are sending an action up to the parent component, todo-widget with a parameter, the text of the input field.

Why send up? Because it’s the parent component, todo-widget, that holds a reference to the data (the array of TO-DO items). So let’s handle this action, pushing a new object onto the todos array:

// app/components/todo-widget.js

import Ember from 'ember';

export default Ember.Component.extend({

  actions: {
    addTodo(text) {
      this.get('todos').pushObject({ text: text });
    }
  }

});

Having a look at our app… it works!

Final touches

Once we submit a new item, the text property keeps its value – but it should be empty!

Additionally, focus should be returned to the input field. We will modify our component behavior:

// app/components/add-todo.js

import Ember from 'ember';

export default Ember.Component.extend({

  actions: {
    submit() {
      const text = this.get('text');
      this.get('onAdd')(text);
      this.set('text', "");
      this.$('input').focus();
    }
  }

});

And that’s much more user friendly.

One of Ember’s conventions is having the application route and application.hbs template as entry points for all other routes and templates.

Let’s check this with an example, opening the template and changing the title:

{{! app/templates/application.hbs }}

<h2 id="title">TO-DO list</h2>

{{outlet}}

{{outlet}} will instruct Ember to include templates of nested routes. In our case (/todos URL), it will include the todos template, which in turn includes our todo-widget.

Try removing {{outlet}} and all the nested templates will disappear.

So there we go! Our beautiful and fully functional Ember app!

For in-depth, step-by-step guides also see:

I hope this helped! Did you enjoy the process? Any questions? I’m happy to hear about all that in the comments below.

Enjoyed this article? Don't miss my next one!

Leave me your e-mail for content that will help you master Ember.js fast:

(A few e-mails per month. No BS. Unsubscribe anytime!)

Do you want to master Ember fast?

Leave me your e-mail for helpful updates delivered straight to your inbox.

(A few e-mails per month. No BS. Unsubscribe anytime!)