Emberjs – A hands on Tutorial

Tweet about this on TwitterShare on LinkedIn0Share on Google+2Share on Reddit0Buffer this pageFlattr the authorEmail this to someonePrint this page

This is a hands on tutorial on Emberjs. We will be covering most of the Ember concepts, so that you can start building Ambitious web apps.

The app which we are going to build is an Online Pizza Store. We will be working with various aspects of Ember in bringing this project to life. The final output would look like

Screen Shot 2015-03-06 at 19.49.56 Screen Shot 2015-03-06 at 19.50.07 Screen Shot 2015-03-06 at 19.50.27 Screen Shot 2015-03-06 at 19.50.52

You can find a live demo of the app here. You can find the completed code here.

So, let us get started.

Mind set

Couple of things before you start working with Ember (totally my opinion)

  1. Emberjs is a “Convention over Configuration” Framework – If you are coming from a traditional web development background, have already worked on frameworks like Backbone or Angular, the coding patterns of Ember may feel very different. And a long term Backbone resource would be utterly confused by how Ember works.
  2. Emberjs has a steep learning curve – If you want to play around with Emberjs building a Hello World app, you would fall in love with it soon. But once you start figuring out things Oh! Boy! it gets tough. I will show you why too.

So, before we proceed, I recommend not bringing your knowledge of other frameworks while working with Ember. Be rooted to the fact that you need to do things the Ember way and thinking otherwise may throw you off track.

And yes, Angularjs also has a steep learning curve too. But because of the framework using HTML for templating and Directives for managing most of the out of box features, Angular is some what easier to get to.

Again, all this is my opinion based on how I felt while I was learning Emberjs.

Hello Ember!

Even before we do anything, we will run a Hello World application, see the output and then continue.

To get us quickly started with an Ember app, the Ember team provides a started kit. If you head to starter-kit repo, you can clone/download it from there. (The ember team has removed the starter kit link from the homepage just a day ago). 

Once you are at the starter-kit repo, you can click on the download button on bottom right hand corner of the page to get a copy of the code.

Once downloaded unzip it and you should see

Screen Shot 2015-03-05 at 15.41.35

The file versions are as of today. To launch the application, you can host it on a LAMP, WAMP, XAMPP or a Python server. Else, if you have Nodejs installed (which I highly recommend having on your machine) you can install a node module named live-server. This is a super awesome node module, that will spawn a static server in the folder from where you are launching, pretty much what we need for this tutorial.

To install, open a new terminal/prompt and run

npm install -g live-server

And then from the folder where you have unzipped the starter-kit, run

live-server

This will spawn a new static server in the current folder and should open the app in your default browser. And also live-server comes with live reload by default. So if we make changes to our Ember app, you need not refresh the web page.

If everything went as expected, you should see

Screen Shot 2015-03-05 at 15.53.56Nothing fancy, just a list of colors being displayed.

Setting up the Ember Inspector

Before we start working with actual Ember code, we will setup the Ember Extension/add-on.

Once you installed the Inspector, you can open your developer tools in Chrome and you should see

Screen Shot 2015-03-05 at 18.07.48And in Firefox open Developer tools NOT Firebug! and you should see

Screen Shot 2015-03-05 at 18.09.33

Ember Concepts

There are a couple of concepts you need to know about Ember before you start playing with it.

  1. Emberjs is a MVC+R (Model + View + Controller + Route) Framework – Ember is heavily route driven when compared with other MVC frameworks. The Ember team believes that the web is URL driven and so should the applications that reside inside them. Hence every “view” is driven via a route. By default there is an Application route that bootstraps the initial application.
  2. Ember has a very strict naming convention in place. Using this Naming convention, the Ember resolver resolves all the routers, controllers, components. So it is very important to understand how Ember expects your app to be structured, so that it can apply the logic you have written.

It is fair to assume that Emberjs does most of the heavy lifting for you, but for you to add customisation to the code, you need to customize routes, controllers, components as needed. This statement would make sense when we start doing some hands on.

MVC+R

Quick overview

  • Model  – Stores Data
  • Views – Displays Data
  • Controllers – Pass the Data from the Model to View (Decorate data)
  • Routes – Invokes a state of the application that triggers a Model > Controller > View

Ember Core Components

Now that we have a context setup and we have seen a basic app, we will take a quick dip into various Emberjs components.

The first and foremost thing you need to do to initialize an Ember app is to execute this line

App = Ember.Application.create();

This tells Ember to initialize a new Ember app and assign it to the App variable. This variable is global and acts like a namespace for our application. Anything that we do from now will be nested inside App.

Routes

Now, when you launch the starter-kit app, and open the dev tools, you will see that there are a few options on the left hand side inside the Ember Inspector.

Screen Shot 2015-03-05 at 18.14.29Select /# Routes  as show above and on the right hand side you would see

Screen Shot 2015-03-05 at 18.15.19

As you can see that Emberjs has already created an Index Route, Controller and Template for you. This is as part of the bootstrapping process.

Now, let us go back the starter app. Open js/app.js in your favourite editor. And where it says

Screen Shot 2015-03-05 at 18.28.55

We will add a new route called about (just for illustration purposes). Update app.js as

Notice Line 5. We have added a new route. Save the file, back to the browser. You should see

Screen Shot 2015-03-05 at 18.32.46We just added a new route and Ember has created a default router, controller, template and URL for this route. This is Ember Magic!

Do notice the names of these components. They all start with the Route Name. When you are in doubt as to what would be the name of a controller for a certain route, you can add that route, open the inspector and Bam!

Now if you want to customize the router (which we would), we will be creating a new AboutRoute  object like

Do notice the naming convention.

And generally here we associate a model like the  IndexRoute

Screen Shot 2015-03-05 at 18.58.15

This brings us to our next component Models

Models

As we already know that Models store data for us. In the  IndexRoute, we are returning an Array of colors. This will then be consumed to display in the template. Sounds simple?

Let us go ahead and add 2 more colors to this list.

Save the file and back to the browser, you should see the 2 new colors reflected in the UI.

Screen Shot 2015-03-05 at 19.03.14

Pretty straight forward.

Controllers

Now, let us say that you want to print the list of colors in ascending order. This is where controllers come in. They decorate your data and make them presentation ready.

Do note that, Models can never talk to Views. It is always the controller that does the communication between them.

To accommodate the new requirement of arranging colors in ascending order, we will create a new controller.

As you might have already guessed, the controller should be named  IndexController.

Add the below code to app.js.

There are quite of lot of things happening in the above code.

  • Line 1 : We extend a new Controller of type Array. There are 2 types of controllers in Emberjs. One is the Object Controller, this controller is used to work with one item in a model. The second one is a Array Controller. This is used to work with an Array of models. This is the one we have used above, since we are dealing with a collection.
  • Line 2 : We create a new function named  sortedModel. This function will return an Array of sorted colors. The syntax  this.get('model') gives us the current model and then we perform a sort() on it and return the sorted array.
  • Line 4 : We return the response of  sortedModel as a computed property. In simple terms,

 A computed property transforms an object’s function into a property.

The Array Controller expects the output of the   sortedModel to be an Array, instead we are returning a function. To patch this, we make this function a computed property.

If you save the file and see the output, there won’t be any change. The list will still be in the same order as we have declared. To make this work, we need to update our template.

Open index.html and take a look at a script tag that looks like

Screen Shot 2015-03-05 at 20.41.49This is a handlebar template with ID as index. Remember we saw the Index template in the inspector, this is where it is coming from. We will talk more about templates in a moment.

For now, replace model  on line 3 above with sortedModel. Save the file and back to browser, you should see

Screen Shot 2015-03-05 at 20.45.21The sorted array!

Now, you can clearly see the amount of learning you need to print an array of colors in ascending order. This is what I meant by learning Ember is steep.

Moving on, we have covered routes, models and controllers. Now finally the Views.

Views

Emberjs uses Handlebar for templating. If you open Index.html, you can see a tag like

This tag stores our templates. And these tags are called as Handlebar Templates. If you notice, we have one more Handlebar template file with id Index. This template will be loaded when we are working with the Index route.

Ember takes care of injecting the model, invoking the controller and parsing the template when we move to a route.

Anything you see in curly braces {{...}}  are called as helpers. Some helpers have a closing as well like the each {{#each}}...{{/each}}. These are called as block helpers.

If you look at the below code

This is the default template that Ember loads while bootstrapping. This template does not have an ID. And do notice the  {{outlet}} helper on line 4. This tells Ember where to place the contents of the child route.

So, in our application, we have a default template that has a heading (Welcome to Ember.js) and we have an Index template when we are on the index route. How will Ember know where to place the contents of the index template? This is where  {{outlet}} helper comes into picture. We will work with  {{outlet}} helper more soon.

Add 2 new MVC+R pieces

Now that we are kind of comfortable with Ember structure, we will add 2 new routes to the application.

  1. About – Will display a static text
  2. Testimonials – Will have a form where the user fills in some text about us and we add that data to the page

So, first we will create 1 new route – testimonials. Since we have already added the about route. The router map would be

about route is static. We do not need a controller for that. We will add only a handlebars template, that has some static data.

Open Index.html and add the about template

Save the files and go back to the browser and navigate to http://0.0.0.0:8080/#/about and you should see

Screen Shot 2015-03-06 at 09.42.20

Simple and easy!

Instead of typing the URL in the browser, we will provide 3 links, that will navigate to the 2 newly created routes and the index route. We will be using a handlebar block helper called as link-to to achieve this.

Update the default template to

The link-to helper takes the route (in quotes) as an argument. If you save the file and go back to the browser, you should see

Screen Shot 2015-03-06 at 09.43.59

If you click on the links, you see the URL/Views changing. Also you can notice that when you navigate to Testimonials, Ember does not throw an error. It shows a default template in it’s place.

Now, let us work on the Testimonials template. The idea behind Testimonial template is that we present the user with a form, where they would enter their name and a message & submit. We will save that data in memory till the user refreshes the page.

So, this is how our template is going to look like

Things to notice

Line 1 : New handlebars template with id testimonials

Line 6 : We will work with a couple of handlebar helper called as input helpers. The out put of line 6 is an input tag. Except, we are adding a new attribute called as value. This value attribute binds with our model named userName. So, we can save the data to our model.

Line 9 : Similar to line 6 except this is a text area and the binding property is message

Line 11 : This is a simple button, that is supposed to invoke a function to save the form data. In Ember, you call methods inside the controller or model using the action helper. Here when we click on the button, a method named  saveTestimonial will be invoked.

Line 14 – 23: We will display all the in-memory testimonials below the form.

Line 15 : We have used another handlebar helper named if. This is a conditional helper. It decides when to show the underlying the content. Here we say that, unless there is at least one testimonial, do not render/show this markup.

Line 17 – 21 : We iterate the in-memory  testimonials array and show the username and message. Pretty straight forward.

If you save the index.html and switch to the browser, you should see

Screen Shot 2015-03-06 at 10.16.41

when you navigate to the testimonials route. A simple form.

Now, to make this form functional, we will add a controller to this route. Add the below code to app.js.

Things to notice :

Line 1 : We have used a Object controller here, because we are going to deal with one testimonial at a time

Line 2 – 4 : We declare 3 properties, that act like model for this template

Line 5 : This is the actions object, which stores a list of methods that can invoked from the view on various user actions.

Line 6 : We have the  saveTestimonial() definition here. We do a simple check of the values and then save it to the  testimonials [].

Line 12 : Notice very carefully that we have used  pushObject() instead of  push() for adding a new object into the   testimonials []. If you use  push() the newly added value will not reflect in the view. This is Ember’s data-binding. We will talk more about it as we go along.

Save all the files and head back to the browser and you should see the same form. But this time, when you enter data, it should reflect below like

Screen Shot 2015-03-06 at 10.31.04

Sweet right! You can try a couple of things. Use push()  instead of pushObject()  and see if things work as expected. And also, after the data is added to the testimonials array, clear the form fields.

Also do note that if you have used  push() while saving the data, it is a one-way data binding. Since we have used  pushObject() it is a two-way data binding.

Data Binding

Let us take a moment in understanding what data binding is all about in Ember. Below are a points from the Ember docs.

  • A binding creates a link between two properties such that when one changes, the other one is updated to the new value automatically.
  • Bindings can connect properties on the same object, or across two different objects.
  • Note that bindings don’t update immediately. Ember waits until all of your application code has finished running before synchronizing changes, so you can change a bound property as many times as you’d like without worrying about the overhead of syncing bindings when values are transient.

This is the glue that connects various pieces of your data together when needed. Also it keeps observing them for changes and can act accordingly.

So far, we have covered most of the core topics that one would need to write a decent application. But we want to build an Ambitious app, so we will dig into couple more core concepts.

  • Ember Object
  • Ember Mixins

Ember Object

Ember.Object is the main base class for all Ember objects.

There is an awesome post by Dan Gebhardt named Understanding Ember.Object, which he wrote exactly 3 years ago. I am going to replicate couple of pieces from same tutorial here.

Creating objects

In ember you can create objects using the syntax

When you create a new object in the console and print the  emberObject, you should see

Screen Shot 2015-03-06 at 11.01.59

There are quite a few properties here and you can explore them from the docs.

To start using the Ember Object, you would use the extend(). Dan Gebhardt used the Person class to explain. I will use a Shape class to explain the same concepts.

Here we create a shape object, that has 2 properties. Now, we will create a new Shape named square.

Now, we can check the inheritance like

A preview of the above in console

Screen Shot 2015-03-06 at 11.21.44Mixins

Another way of implementing complex object in Ember is to use a Mixin. Quoting an example from  Understanding Ember.Object

While extending classes in a hierarchical fashion often works well, there is a tendency to end up with classes such as MaleLeftHandedPetOwnersOfPoodles. Trying to munge together a bunch of separate concerns in a single class can get messy. Ember’s answer to this problem isEmber.Mixin.

With this we have covered most of the essential concepts in Emberjs. There is still a Lottttt left to learn in Ember.

Now, We will be building an Online Pizza Store example using all the above concepts and Ember Data.

So, let us get started.

Online Pizza Store

Application Design

This is a simple website that presents a list of Pizza that a store sells. A user would select the pizza he want and places an order. The app will accept the order and show the same in order history. At a high level there would be 4 pages

  1. Home Page
  2. List of Pizzaz
  3. Pizza Cart Page
  4. Order History

We will not be adding authentication piece for this example.

First thing we do is list out the routes. We will 4 routes and 1 sub-route.

  1. #/pizzaz – Lists all pizzaz
  2. #/pizza – Shows the selected pizza details
  3. #/cart – Shows the pizzaz added to cart
  4. #/history – Show the order history
    1. #/history/details – Show the order details for a given order

Next, we will chalk out Models. There will be 3 models

  1. Pizza Model
  2. Cart Model
  3. History Model

We will be using Ember data and FixtureAdapter to manage the data.

Setup the Project

You can unzip another copy of starter-kit-master and rename it to online-pizza-store. We will be modifying the same template to achieve the online pizza store app.

As mentioned earlier, we will be using Ember Data for managing the data. So, we will download Ember data. Navigate to Tagged Releases, scroll to the very bottom and you should find Ember Data tagged Builds. Below that you can pick a version – tags/v1.0.0-beta.15/ember-data.prod.js. As of today, this is the latest version. You can download the same from here. Save the file to js/libs folder.

Next, for some look and feel, we will add Bootstrap CSS. Head over to getbootstrap.com and either copy the bootstrap.css reference or download a copy of it to your /css folder. Do the same for bootstrap.min.js too.

Next, we will refer the 3 files in index.html. The updated index.html would be

Setup Routes

Next, we will setup the router and routes. The starter template has all the Ember components in one file. This gets kind of messy when we start building an app like the Online Pizza Store. So, we will split the app.js file into multiple files, based on Ember component type.

Create the following files inside the js folder

  • adapter.js – To work with Adapters
  • app.js – App init code
  • components.js – To work with custom components
  • controllers.js – To work with controllers
  • fixture.js – Holds sample data for the app
  • models.js – To work with models
  • router.js – To work with router
  • routes.js – To work with routes

Open app.js and update it as below

Now, we will add a router. Open router.js and update it as

Things to notice

Line 3 : We add the pizzaz route

Line 5 : We add the pizza route that takes in the pizza id as a param

Line 9 : We add the cart route

Line 11 : We add the history route.

Line 12 : Once the history route is registered, we will add a sub-route or a child route which shows the details of the order.

We will look at difference between pizza route and details route when we work with them.

Setup FixtureAdapter

We are going to add a new Application Adapter. Adapters are the way Ember models communicate with the data. Since this is a tutorial app, we will be using memory as our data store. We will enable this using the FixtureAdapter.

Open adapter.js and update it as

Things to notice

Line 1 : We have extended a FixtureAdapter

Line 2 – 8 : We have written a logic to return only a few records from the fixture, if we pass in a start and end value. If you did notice the home page of the app, we have only 4 pizzaz listed at the bottom. We achieve that using the logic written here. The same logic can be used for pagination when using FixtureAdapter.

Setup Fixture data

To work with FixtureAdapter, we need fixture data. So, open fixture.js and update it as

As you can see from above, we are referring to some images. You can get the images from here.

Setup IndexRoute

Next, we will add the definition for IndexRoute. This will load 4 pizzaz from the fixture data. Open routes.js and update it like

If you refer the FixtureAdapter code above, we are passing in the complete array of 8 items and fetching only 4 back here.

Setup Models

Now, we will create the models. Open models.js and update it as

Things to notice

Line 1 :  We extend a pizza model. Do notice that we are using DS (data store)’s version of model here. We have 3 properties. pizza name, pizza image and pizza description. Even though our fixture data is having an ID, we do not add it. Emberjs takes care of it.

Line 7 : We extend a cart model from DS.Model. This model will consist of a list of pizzaz that are present in the current order.

Line 11 :  We extend a history model from DS.Model. This model will consist of all the orders placed so far.

Line 15 : We feed the fixture data from fixtures.js to the Pizza model, using the reopenClass syntax.

Line 19, 20 : We assign empty data to cart and order history.

Next, a bit off CSS to beautify the page. Open css./style.css and update it as below

Update IndexTemplate

To complete the index route, we will update the template. After updating the template and adding reference to all the js files, it would look like

Quite a lot things have changed. Let me walk you through

Lines 12 – 34 – Is the default template. This consist of the navbar and the outlet. Nothing fancy.

Lines 36 – 49 –  This is our index template. Lines 37-42 consist of a promo banner with a button going no where. Lines 44 – 48 iterate over the sub-array of pizzaz and display them. There are multiple places in the application, where we display one pizza entity. So I though why don’t we make this a component. So, on line 46, I am invoking a single-pizza custom component and passing in the current pizza as a argument.

Lines 51 – 65 – This consist of the markup for single-pizza component. Do notice the id on the script tag. It is  components/single-pizza. Yes, this is how Ember expects a component to be created.

You can read more about Ember components here. And Ember’s implementation is close to Web Components spec. You can read more about it here and here.

If you saved all the files and went back to the browser, assuming you have launched a new live-server in the current folder, you should see

Screen Shot 2015-03-06 at 19.49.56

Setup PizzazRoute

Next, we will create the pizzaz route. This will list all the pizza in the fixture data. Open routes.js  and add the below code to it

This route returns all the pizza models.

Next, we will add the pizzaz template. Add the below template after the Index template in index.html

I guess you can understand what is going on above.

If you save all the files and navigate to the pizzaz route, you should see

Screen Shot 2015-03-06 at 21.18.41

Setup PizzaRoute

Next, we will setup PizzaRoute. When the user clicks on View button, we will show him the details of the pizza.

Open routes.js and add the below code

Here we fetch the ID value from params and then  load the corresponding model.

The template for this would be

Do notice line 5. We have added another component called back-button. The purpose of this component is to render a back button and navigate to one page before. The template is on line 33. We will add a action and then perform the back logic there.

Open components.js and update it as below

Observe the naming convention!

Line 26 in our template snippet above, has an action named addToCart. This will add the current pizza to cart. We will write the related logic in controllers.js.

Things to notice

Line 5 : We get all the items in the cart. This is a async operation and returns a promise

Line 6 : We read the existing items

Line 10 : We assign the id as the length of the cart array

Line 11 : We add the pizza object to the current cart.

Line 18 : We save the updated cartItem to Cart model

Line 19 : We take the user to the cart route.

Save all the files and when you click on View button on any pizza and you should see

Screen Shot 2015-03-06 at 19.50.07and when you click on add to cart, you should see the pizza added to cart. And if you go back to the Pizzaz page and add couple more, they should be added to the current cart as shown below.

Screen Shot 2015-03-06 at 19.50.27

Setup CartRoute

Now that we can see individual pizzaz, we will provide the user to add this pizza to cart. Open routes.js and add the below

Very straight forward. we return the data from cart model. This will be empty every time you refresh the page. Do remember, we are using using FixtureAdapter, which stores the data in-memory.

Next, the template. Add the below template to index.html

Things to notice

Line 9 : We are using a handlebars helper named if. This shows or hides the markup nested inside it based on the value of model

Line 15 : unless helper is the opposite of if helper. This is true for all falsy values, where as if is true for all truthy values.

Line 11 : We have added an action named checkout. This will move all the pizzaz in the cart to the order history model.

Next, the controller logic for the checkout action. Add the below code to controllers.js

Here, we first fetch list of items in the cart and then add it to the order history as one item. The logic is pretty straight forward.

Setup HistoryRoute & HistoryDetails Route

The final route of our application. This view will be a nested view. Nested view as in, when the URL changes, we do not navigate away from the current page. But rather, we update a section of the page with new data. This kind of layout is also called as mater-detail layout.

The master data here is the list of order and the detail is the order details for each order.

Update route.js  with below code

And the index.html with all the templates would be

Notice line no 117. This is where the order details data gets injected.

Save all the files and you can perform a complete flow of the app.

You can view pizza, add to cart. View another pizza, add to cart. Then checkout. The you can click on order 0 link and you should see the above 2 pizzaz. You can repeat the same for another order and you should see the order history updated.

Once you refresh the page, the cart and history data will be lost.

This brings us to the end of the Emberjs – Hands on tutorial. Hope you guys learnt a few things about Emberjs.


Thanks for reading! Do comment.
@arvindr21

Tweet about this on TwitterShare on LinkedIn0Share on Google+2Share on Reddit0Buffer this pageFlattr the authorEmail this to someonePrint this page
  • Alistair Buckle

    Really enjoying this tutorial – thanks!

    I had a similar problem to the ArrayController with the Testimonials ObjectController (maybe both are removed in the starter-kit version of Ember (currently: 2.0.1)?) so I changed the declaration of the controller:

    App.TestimonialsController = Ember.Controller.extend…

    and in the Testimonials view:
    {{#each testimonials as |item|}}

  • Vickie Eileen Allen

    I am very new to Ember – when I get to sorting the list of colours – I follow the tutorial exactly but I get an Uncaught TypeError: Cannot read property ‘extend’ of undefined(anonymous function) @ app.js:15

    How can I solve this?

    Vickie

    • Alistair Buckle

      I’m new to Ember too but it looks like there was a problem with ArrayController.extend(), possibly because ArrayController is deprecated or removed in Ember. I sorted the model using a Controller instead:

      App.IndexController = Ember.Controller.extend
      (
      {
      sortedModel: Ember.computed( ‘model.[]’, function()
      {
      return this.get( ‘model’ ).sort()
      }
      )
      });

      • nemo b

        I’m surprised your comment hasn’t gotten more attention. I struggled with this step for a solid 10 min before thinking to look in the comments section. Thank you!

  • vishal giri

    Thanks Arvind Great work.

  • Levi Taule

    An excellent “quick dive-in” article which persuaded me to use EmberJS in my current project.