Advertisement
JavaScript & AJAX

Getting Into Ember.js: Part 5

by

Editor's Note: The Ember.js team has shifted to an expedited release schedule and as of this publication date are on version 1.2.0. This tutorial was written pre-v1.0 but many of the concepts are still applicable. We do our best to commission timely content and these situations happen from time-to-time. We'll work to update this in the future.

In part 3 of my Ember series, I showed you how you can interact with data using Ember's Ember.Object main base class to create objects that define the methods and properties that act as a wrapper for your data. Here's an example:

App.Item = Ember.Object.extend();

App.Item.reopenClass({
  all: function() {
    return $.getJSON('http://api.ihackernews.com/page?format=jsonp&callback=?').then(function(response) {
      var items = [];

      response.items.forEach( function (item) {
    items.push( App.Item.create(item) );
  });
  return items;
});

In this code, we subclass Ember.Object using the "extend()" and create a user-defined method called called "all()" that makes a request to Hacker News for JSON-formatted results of its news feed.

While this method definitely works and is even promoted by Ember-based Discourse as their way of doing it, it does require that you flesh out and expose the API that you'd like to reference the data with. Most MVC frameworks tend to include ORM-like capabilities so if you're used to Rails, for example, you'd be very familiar with the benefits of ActiveRecord which helps to manage and do the heavy lifting of interacting with data.

The Ember team has wanted to do the same thing but their main focus has been to get a stable v1 release of their core framework out first to ensure that complementary components could be built on a stable foundation. I actually applaud this and I actually made mention of the fact that you should hold off on using Ember Data because of this.

Now that Ember RC8 is out and v1 seems to be coming around the corner, I felt it was a good time to start exploring Ember Data and see what it offers.

Ember Data

The first thing I want to stress is that Ember Data is a work in progress and in much the same way as Ember started, will probably see a number of breaking API changes over the next several months. While that's not ideal, it's important to begin looking at how you would structure your apps using the library. To give you a good description of what Ember Data provides, I've copied in the well-written description from the GitHub page:

Ember Data is a library for loading data from a persistence layer (such as a JSON API), mapping this data to a set of models within your client application, updating those models, then saving the changes back to a persistence layer. It provides many of the facilities you'd find in server-side ORMs like ActiveRecord, but is designed specifically for the unique environment of JavaScript in the browser.

So as I mentioned, it's meant to abstract out a lot of the complexities of working with data.

Using Ember Data

If you've read my previous tutorials, you should be very familiar with how to set up a page to leverage Ember. If you haven't done so, you should go to the Ember.js home page and grab the Starter Kit. You can find it right in the middle of the page as it's displayed via a big button. This will give you the most up-to-date version of Ember which you'll need in order to work with Ember Data. The easiest way to get a downloadable version of Ember Data is to go to the API docs for models, scroll to the bottom and download the library. Additionally, you can go to the builds page to pull down the latest builds of any Ember-related library.

Adding Ember Data is as simple as adding another JavaScript file to the mix like this:

<script src="js/libs/jquery-1.9.1.js"></script>
<script src="js/libs/handlebars-1.0.0.js"></script>
<script src="js/libs/ember-1.0.0-rc.8.js"></script>
<script src="js/libs/ember-data.js"></script>
<script src="js/app.js"></script>

This now gives you access to Ember Data's objects, method and properties.

Without any configuration, Ember Data can load and save records and relationships served via a RESTful JSON API, provided it follows certain conventions.

Defining a Store

Ember uses a special object called a store to load models and retrieve data and is based off the Ember DS.Store class. This is how you'd define a new store:

App.Store = DS.Store.extend({
...
});

If you remember from my previous articles, "App" is just a namespace created for the application level objects, methods and properties for the application. While it's not a reserved word in Ember, I would urge you to use the same name as almost every tutorial and demo I've seen uses it for consistency.

The store you create will hold the models you create and will serve as the interface with the server you define in your adapter. By default, Ember Data creates and associates to your store a REST adapter based off the DS.RestAdapter class. If you simply defined the code above, you would have an adapter associated to it by default. Ember magic at its finest. You can also use a Fixture adapter as well if you're working with in-memory-based data (for example, JSON you're loading from code) but since this is about making API calls, the REST adapter is more appropriate.

You can also define your own adapter for those situations where you need more custom control over interfacing with a server by using the adapter property within your store declaration:

App.Store = DS.Store.extend({
  adapter: 'App.MyCustomAdapter'
});

Defining Models

The code I listed at the top of this tutorial was an example of how to use Ember.Object to create the models for your application. Things change a bit when you define models via Ember Data. Ember Data provides another object called DS.Model which you subclass for every model you want to create. For example, taking the code from above:

App.Item = Ember.Object.extend();

It would now look like this:

App.Item = DS.Model.Extend()

Not much of a difference in terms of appearance but a big difference in terms of functionality since you now have access to the capabilities of the REST adapter as well as Ember Data's built-in relationships like one-to-one, one-to-many and more. The main benefit, though, is that Ember Data provides the hooks for interacting with your data via your models as opposed to you having to roll your own. Referencing the code from above again:

App.Item.reopenClass({
  all: function() {
    return $.getJSON('http://api.ihackernews.com/page?format=jsonp&callback=?').then(function(response) {
      var items = [];</p>

     response.items.forEach( function (item) {
    items.push( App.Item.create(item) );
  });
  return items;
});

While I had to create my own method to return all of the results from my JSON call, Ember Data provides a find() method which does exactly this and also serves to filter down the results. So in essence, all I have to do is make the following call to return all of my records:

App.Item.find();

The find() method will send an Ajax request to the URL.

This is exactly what attracts so many developers to Ember; the forethought given to making things easier.

One thing to keep in mind is that it's important to define within the model the attributes you plan on using later on (e.g. in your templates). This is easy to do:

App.Post = DS.Model.extend({
     title: DS.attr('string')
});

In my demo app, I want to use the title property returned via JSON so using the attr() method, specify which attributes a model has at my disposal.

One thing I want to mention is that Ember Data is incredibly picky about the structure of the JSON returned. Because Ember leverages directory structures for identifying specific parts of your applications (remember the naming conventions we discussed in my first Ember article?), it makes certain assumptions about the way that the JSON data is structured. It requires that there be a named root which will be used to identify the data to be returned. Here's what I mean:

{
  'posts': [{
    'id': 1, 
    'title': 'A friend of mine just posted this.',
   'url': 'http://i.imgur.com/9pw20NY.jpg'
  }]
}[js]

<p>If you had defined it like this:</p>

[js]{
{
    'id': '1', 
    'title': 'A friend of mine just posted this.',
    'url': 'http://i.imgur.com/9pw20NY.jpg'
  },
{
    'id': '2', 
    'title': 'A friend of mine just posted this.',
    'url': 'http://i.imgur.com/9pw20NY.jpg'
  },
}

Ember Data would've totally balked and thrown the following error:

Your server returned a hash with the key id but you have no mapping for it.

The reason is that since the model is called "App.Post", Ember Data is expecting to find a URL called "posts" from which it will pull the data from. So if I defined my store as such:

App.Store = DS.Store.extend({
  url: 'http://emberdata.local' 
});

and my model like this:

App.Post = DS.Model.extend({
     title: DS.attr('string')
});

Ember Data would assume that the Ajax request made by the find() method would look like this:

http://emberdata.local/posts

And if you were making a request for a specific ID (like find(12)), it would look like this:

http://emberdata.local/posts/12

This issue drove me batty, but doing a search found plenty of discussions on it. If you can't set up your JSON results in this way, then you'll have to create a custom adapter to massage the results to properly serialize them before being able to use it. I'm not covering that here but plan to explore more of that soon.

The Demo App

I purposely wanted to keep this tutorial simple because I know Ember Data is changing and I wanted to give a brief overview of what it provided. So I whipped up a quick demo app that uses Ember Data to pull JSON data from my own local server. Let's look at the code.

First I create my application namespace (which you would do for any Ember app):

// Create our Application
App = Ember.Application.create({});

Next, I define my data store and I declare the url from where the model will pull the data from:

App.Store = DS.Store.extend({
  url: 'http://emberdata.local'; 
});

In the model, I specify the attribute: title, which I'll use in my template later on:

// Our model
App.Post = DS.Model.extend({
     title: DS.attr('string')
});

Lastly, I associate the model to the route via the model hook. Notice that I'm using the predefined Ember Data method find() to immediately pull back my JSON data as soon as the app is started:

// Our default route. 
App.IndexRoute = Ember.Route.extend({
  model: function() {
    return App.Post.find();
  }
});

In the template for the root page (index), I use the #each Handlebars directive to look through the results of my JSON data and render the title of each of my posts:

<script type="text/x-handlebars" data-template-name="index">
    <h2>My Posts</h2>
    <ul>
    {{#each post in model}}
        <li>{{post.title}}</li>
    {{/each}}
    </ul>
  </script></p>

That's it! No Ajax call to make or special methods to work with my data. Ember Data took care of making the XHR call and storing the data.

Fin

Now, this is incredibly simplistic and I don't want to lead you to believe it's all unicorns and puppy dogs. As I went through the process of working with Ember Data, I found myself wanting to go back to using Ember.Object where I had more control. But I also realize that a lot of work is going on to improve Ember Data, especially in the way it manages diverse data results. So it's important to at least kickstart the process of understanding how this thing works and even offering constructive feedback to the team.

So I urge you to jump in and begin tinkering with it, especially those that have a very strong ORM background and could help shape the direction of Ember Data. Now is the best time to do that.

Related Posts
  • Code
    Android SDK
    Create a Music Player on Android: Project Setup0d63m preview image@2x
    The Android platform provides resources for handling media playback, which your apps can use to create an interface between the user and their music files. In this tutorial series, we will create a basic music player application for Android. The app will present a list of songs on the user device, so that the user can select songs to play. The app will also present controls for interacting with playback and will continue playing when the user moves away from the app, with a notification displayed while playback elapses.Read More…
  • Code
    JavaScript & AJAX
    Ember Components: A Deep DiveEmber components retina preview
    Ember.js is a JavaScript MVC framework that allows developers to create ambitious web applications. Although pure MVC allows a developer to separate concerns, it does not provide you with all the tools and your application will need other constructs. Today, I'm going to talk about one of those constructs. Ember components are essentially sandboxed re-usable chunks of UI. If you are not familiar with Ember, please check out Getting Started With Ember.js or the Let's Learn Ember Course. In this tutorial, we will cover the Web Components specification, learn how to write a component in Ember, talk about composition, explain the difference between an Ember view and an Ember component, and practice integrating plugins with Ember components.Read More…
  • Code
    JavaScript & AJAX
    Introduction to Sails.jsSails preview 400 2
    Sails is a Javascript framework designed to resemble the MVC architecture from frameworks like Ruby on Rails. It makes the process of building Node.js apps easier, especially APIs, single page apps and realtime features, like chat.Read More…
  • Code
    JavaScript & AJAX
    Integrating a JS Build Process Into MSBuild in Visual Studio 2012 ExpressMsbuild retina preview
    I've been working with ASP and ASP.NET for about ten years now, starting with ASP classic and settling on .NET 2.0 as my favorite. My new year resolution this year (2013) was to upgrade my .NET work to .NET 4.0 using Visual Studio 2012 Express and really get to grips with MSBuild, so that I can concatenate and minify my JavaScript files as part of the normal build process of a .NET project, in Visual Studio. My first love is to use Ant in NetBeans with a PHP or JSP platform for this kind of work, but my company's main website runs on a .NET platform and it's time to update it, so I decided to bite the bullet and dive back in to some serious study of creating a fully integrated build process using MSBuild. This tutorial will show you how to edit your Visual Studio 2012 Express project file to include your own separate build file which will perform the now widely familiar process of concatenating and minifying a set of JavaScript modules into one file ready for deployment. Read More…
  • Code
    JavaScript & AJAX
    Getting Into Ember: Part 4Getting into ember
    In my previous tutorial, I touched on how to use Ember.Object to define your models and work with datasets. In this section, we'll look more closely at how Ember uses the Handlebars templating framework to define your app's user interface.Read More…
  • Code
    JavaScript & AJAX
    Getting Into Ember.js: Part 3Getting into ember
    I hope that you're starting to see that Ember.js is a powerful, yet opinionated, framework. We've only scratched its surface; there's more to learn before we can build something truly useful! We'll continue using the Ember Starter Kit. In this portion of the series, we'll review accessing and managing data within Ember.Read More…