Content with Ember.js
Ember.js is a framework for creating ambitious web applications. The official site offers guides and api documentation, which are currently quite good – so if you are not familiar with Ember.js take a tour in the guides and you will find out all the goodness about it.
As for myself, I’ve been a web developer for a while. Most of my time has been spent in PHP coding, but during that I have gained quite a lot of HTML/CSS and JavaScript experience. The latter I’ve actually come to enjoy the most. This has somewhat moved me away from PHP and closer to JavaScript, in the browser and on the server, with Node.js.
And while trying to be as productive as possible with my projects, I have met Ember.js. Since then, we have become good friends.
Modern content
Presenting content on the internet is different from what it was a few years back. Providers are trying to make it as beautiful as possible, they are trying to reach as many users as possible, and most importantly, they are trying to make the experience of consuming content as enjoyable as possible.
This last goal is where JavaScript frameworks come into the process. Using these, providers can publish their content in the most usable form, allowing users to interact with it, to share it, and contribute to it.
At this point say hi to Ember.js. By using it, I am able to provide a great experience for my users. Let us look at this in a bit more detail.
Building the application
The easiest way of starting up with Ember.js, is to use the Starter Kit provided on the Ember.js homepage. After you have downloaded and unpacked it, you will notice that they provide almost everything you need for starting up. Even a TODO.txt, which is a short description of how to go on.
For the purpose of this post, we will not handle CSS, meaning looks are not important right now, styling should be as decoupled as possible from the JavaScript.
Let’s start with looking at the app.js.
App = Ember.Application.create();
App.Router.map(function() {
// put your routes here
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['red', 'yellow', 'blue'];
}
});
As you may have already noticed, we already have the code for creating our sample App, for the definition of our Router and also the first route, which is the Index route. This already contains some code, which we will soon change.
The first thing you should think about is, how does Ember.js know what to display? Well, Ember.js is really smart and if you do not tell it what to display in certain situations, it figures it out for itself.
Take for instance the Index Route, which is defined. We can tell from the code that the model of the Route is defined, which ends up in passing some data to a view. But where is that view? If you open the index.html you will notice in it a script tag, which contains some interesting code. The first one is the one which has an {{outlet}}
inside of it. By definition, an outlet is a placeholder of the content Ember.js will generate for you. The script that contains it is a template. Ember.js uses templates for displaying content, which are basically the grounds of the view layer.
This template is dedicated to our application – everything we do from now on will be displayed here, more precisely inside the {{outlet}}
and due to it not having a name, Ember.js knows it is the application’s main template.
There is another template in the index.html source. This one has a name, data-template-name="index"
. By convention, this will be our index template. But why?
Taking a closer look at the name of the template, we see it is index. Also, the name of the Index Route would be index, so Ember.js knows it should be looking for a template named like that and display it into the application’s outlet.
Routes
I’ve been mentioning these routes so much, but what are they? To look at it in a simple way, routes are URLs into our application, which identify certain parts of it, like the index for example. Let’s put a bit more code inside the app.js:
App = Ember.Application.create();
App.Router.map(function() {
this.route("index", {path: "/"});
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ["red", "yellow", "blue"];
}
});
As you can see if you refresh the page, nothing has changed. This has a very simple explanation: that line of code we put in there: this.route("index", {path: "/"});
was previously generated for us by Ember.js – it knows that this is how it should look. How awesome is that?
Let’s just create a few more routes for our little app and clean it up a bit.
App = Ember.Application.create();
App.Router.map(function() {
this.route("channelr", {path: "/:url"});
this.route("postr", {path: "/:channel/:url"});
});
Things are getting interesting. What we just did, is define two routes which will be the two of our app’s three routes, the index being generated. Basically they describe a post category URL and post detail URL, in that order. The parts in the path preceded by :
are dynamic and will be replaced by our app at a later point.
Due to the routes being totally dynamic, we need to add some more code, which will handle the dynamics:
App.ChannelrRoute = Ember.Route.extend({
serialize: function(model) {
"use strict";
return {
url: model.get("url")
};
},
setupController: function(controller, model) {
"use strict";
var url = model.get("url");
controller.set("channels", App.Channel.find());
controller.set("posts", App.store.filter(
App.Post, function(data) {
if (url === "") {
return true;
} else if (data.get("channel") === url) {
return true;
}
})
);
}
});
App.PostrRoute = Ember.Route.extend({
serialize: function(model) {
"use strict";
return {
channel: model.get("channel"),
url: model.get("url")
};
},
setupController: function(controller, model) {
"use strict";
controller.set("channels", App.Channel.find());
controller.set("post", model);
}
});
In both routes above, the serialized method helps Ember determine the dynamic segments in the paths. The other method, setupController
, is a hook provided by Ember routes where you can set data to be displayed in the browsers.
There are a few new things there. Models for instance. In Ember, they basically contain data, to put it simply. When you want to present the user a post, then that post’s data is contained within a model.
There are more new things here: App.Channel.find()
. This basically retrieves a list of channels, or categories if you are familiar with WordPress. Then, the controller.set("channels", App.Channel.find());
part sets the data to be displayed into a template.
The above code is probably the core of Ember: controllers set and deliver model-contained data to views.
For the find methods to work, we need to tell Ember where it can find data. There is a extension called Ember-data that we’ll use for this purpose.
App.store = DS.Store.create({
adapter: "DS.FixtureAdapter"
});
App.Post = DS.Model.extend({
title: DS.attr("string"),
url: DS.attr("string"),
channel: DS.attr("string"),
body: DS.attr("string")
});
App.Channel = DS.Model.extend({
title: DS.attr("string"),
channel: DS.attr("string"),
url: DS.attr("string")
});
The entity that Ember uses for retrieving data is called a store. This has adapters of a few types, REST
or maybe a localStorage
interface, or you can even write your own special adapter like many have done so far.
For the store to work, we also need to define data, just like you would do in a classical database table create statement. We have two types of models here: the channels and the posts.
Usually, for getting/setting data I would use the REST adapter, which is a very simple way of of communicating with your server, without writing ajax code. But for the purpose of this article, we’ll use the FixtureAdapter
which is basically a full client-side data store: you feed it some JSON and it creates models for you. The JSON is in the Github repository, due to it being too big for this post.
There is one more aspect of the applications that we didn’t talk about: the way Ember displays the data. For this purpose, we’ll use partials, which are simple bits of HTML basically included where you want them to, exactly like include statements in PHP.
First, let me just show you the templates for the four views:
<script type="text/x-handlebars">
<h2>My Blog</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
{{partial header}}
{{partial posts}}
</script>
<script type="text/x-handlebars" data-template-name="channelr">
{{partial header}}
{{partial channel}}
</script>
<script type="text/x-handlebars" data-template-name="postr">
{{partial header}}
{{partial post}}
</script>
It might seem complex, but it is actually quite simple. The first one is the application template, the others are for the index route, then the channel and the post route. The {{outlet}}
is the container of all the others, that is where Ember will generate them.
All have one partial in common, the header, which will hold the menu. The other partials are dedicated to displaying post lists and posts. Let’s see now how the partials look like:
<script type="text/x-handlebars" data-template-name="_header">
<ul>
{{#each channel in channels}}
<li>
{{#linkTo "channelr" channel}}{{channel.title}}{{/linkTo}}
</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="_posts">
<ul class="clear">
{{#each post in posts}}
<li class="clear">
<h2>{{#linkTo "postr" post}}{{post.title}}{{/linkTo}}</h2>
</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="_channel">
<ul class="clear">
{{#each post in posts}}
<li class="clear">
<h2>{{#linkTo "postr" post}}{{post.title}}{{/linkTo}}</h2>
</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="_post">
<article class="clear">
<h2 class="clear">{{post.title}}</h2>
<div class="clear">{{post.body}}</div>
</article>
</script>
The above are basically average handlebars templates. You can read more about that on handlebarsjs.com
Also, I strongly recommend visiting the Ember guides for getting a deeper impression on Ember.js, paying attention especially to the parts we have used above: routing, models, views and controllers in general, Ember-data and the REST adapter, JSON response structure and fixtures.
Conclusion
I mentioned modern content somewhere above. Imagine content displayed in a great way, which reacts really well to your clicks and taps. A content which you don’t have to wait for while it is loaded after you clicked, because it is already there. Imagine you can share or change content just as you do on Facebook or Twitter. And in the end, imagine how good content creation would feel in such a environment.
Source
I have put all the app on Github. If you just clone it, then open the index.html
inside the app folder, it should work perfectly. If not, just hit me on one of the below and I will help.
How can you reach me?
I have a bog eduardmoldovan.com, a twitter profile @edimoldovan and a Github account edimoldovan.