May 11, 2015
Table of contents:
The majority of web applications aren’t going to be very useful without data.
In a typical MVC application, it is the model layer that usually deals with the data of the application. In single page applications this is usually in the form of a JSON API to some kind of backend service.
In today’s tutorial we’ll be looking at Models in Ember.js, and in particular, Ember Data.
So far in this deep dive into Ember, we’ve already seen how we can provide the Route with the model data (Working with Routes in Ember.
The Template can access this model data by using the Controller as a proxy (Using Controllers in Ember).
In Working with Routes in Ember we looked at a simple example where we provided an object of data.
But of course, you would never hard code your data into your application!
Instead you can use Ajax requests to get data from your JSON API directly from the route:
App.PostsRoute = Ember.Route.extend({
model: function () {
return Ember.$.getJSON("/api/posts");
},
});
This will enable you to very easily integrate your API with your Ember application.
Using Ajax requests is a good place to start when you are first getting a handle on Ember.
However, it’s probably going to get too complicated as your application grows.
As with traditional server side applications, we don’t usually deal with getting data to and from the database and converting it into objects.
Ember Data is a model library that manages finding data, making changes, and saving it back to the server.
It’s a bit like an ORM in that it abstracts the underlying persistence mechanism behind an easy to use API. If you’re familiar with using ORMs, you will find Ember Data easy to work with.
Another really nice feature of Ember Data is that it maintains an identity map of your application data. This means that if you request data that has already been loaded, Ember will return the data from the Identity Map and save your from making an additional request to the server.
As you can probably guess, building a library that embodies many of the qualities of an ORM isn’t exactly a piece of cake.
In order to understand Ember Data and how it works, first it’s important to understand a couple of important concepts.
The Store is the main interface of Ember Data. You can think of The Store as the central repository of Ember Data. If you’ve used something like Doctrine in PHP, it’s a bit like the Entity Manager.
Whenever you pull data from your API, a copy of it will be cached in the Store. This means that if the Store already has a copy of your data, it doesn’t need to request if from the API.
The Store is made available to you in both the Routes and Controllers of your Ember application.
App.PostsRoute = Ember.Route.extend({
model: function () {
return this.store.find("posts");
},
});
If you’re familiar with Laravel’s Eloquent or Rails’ ActiveModel, you will already understand Ember Models.
A Model is basically the blueprint that defines the properties and relationships of the important objects of your application:
App.Person = DS.Model.extend({
title: DS.attr("string"),
published_at: DS.attr("date"),
body: DS.attr("string"),
comments: DS.hasMany("comment"),
});
A Record is an instance of a Model that contains data. When you search the Store, you will be returned a collection of Records.
Again, if you’ve worked with just about any ORM in the past, this concept should be pretty straight forward to you:
this.store.find("posts", 464);
The request above would return the following object:
{
id: 464,
title: "Introduction to Ember Data",
body: ".."
}
The Adapter is responsible for actually making the request to your server. Ember Data is agnostic to the persistence mechanism, and so it is up to the Adapter to actually do the work of fulfilling the requests.
If you are using the typical JSON API set up, you’re probably going to use the Ember REST Adapter.
And finally, Serializers are used to take the response from the Adapter and convert it into an Ember Data object.
This keeps the line of separation between your application and the adapter clear by providing a more agnostic interface to Ember Data.
Don’t worry if this all feels overwhelming, we’ll be looking at each aspect of Ember Data in detail over the coming weeks!
So now that you’ve got a clearer understanding of each of the main components of Ember Data, we’ll take a brief look at how Ember Data actually works.
When you make a request in your application (e.g /posts/1
), Ember Data will check the Identity Map to see if the data object has already been loaded.
If the Identity Map does not contain the data it will make a request to the Adapter.
The Adapter will return a promise and then make a request to the persistence store for the data. A promise is returned when the process has to make an asynchronous request. When the request has the data, it will return the data to the promise.
The JSON data is serialised into an Ember Data object and returned from the Store to the application.
If the data was in the Identity Map, the data would be returned from the promise immediately.
Ember Data will feel very familiar and intuitive if you’ve ever worked with a similar ORM type layer. Abstracting the complications of retrieving data and making requests whilst still providing an easy to work with API is no mean feat.
Of course, Ember Data won’t be the right solution for every project. If you are developing an really unique application with custom requirements, you might find Ember Data more hassle than it’s worth.
But either way, I would recommend you take a look at using Ember Data for your next Ember project.