The Ember Path

work safe

There was a recent blog post by Rob Conery about learning EmberJs by just flinging yourself at it. That was something that kind of resonated with me. I’ve been trying to understand EmberJS for a while, but I wasn’t getting it. I wasn’t feeling confident enough to actually start a project and get it right. You can never learn without actually doing and Rob reminded me of this.

So I tried it. I flung myself in to the void of two projects.

Define the Problems

I chose two projects.

Project one is a rewrite of a comic strip site I wrote using JavaScript and HTML in about 2002. Considering I’ve not written anything for the comic itself in almost 10 years, It’s not important, but it is a healthy amount of data to display.

Project two is much smaller and uses an ASP.NET web service to wrap the Microsoft Exchange APIs. It simply asks what is currently happening with the different conference rooms at SEP.

Layout the path

I wrote both of the sites using mostly the same path. I wrote them at about the same time, so this is only logical. I accepted as fact that I would be rewriting functionality and moving code between responsibilities as I got more familiar with Ember’s various pieces.

Wonder Twins Routes and Templates (via URLs)

With routes and templates, a large amount of the work can be done. I can lay out a number of screens and how they transition. I can specify the Urls for each page.

According to Tom and Yehuda, the Ember core team, The heart of a web application is the URL and the Router is how Ember interfaces with them.

Some Urls map to a route literally to a template. The Comic’s about page has no logic or data. It’s just text. Navigating to the /about Url displays the “about” template.

App.Routes.map(function(){
    this.route("about", {path: "/about"});
    ...
});

The template uses Handlebars wrapped in a script tag. The element ID is used to map the name to the route.

<script type="text/x-handlebars" id="about">
  Some About Text
</script>

Wait, there’s data?

If we want to add a touch of data to a page, we can change the route. Let’s look at the cast page. We don’t alter how we define the route mapping.

    this.route("cast", {path: "/cast"});

Then we can override the default router by adding a touch of code. Here, we have a static data structure defining our cast members. I then override the default router for the Cast route and define a model attribute.

var cast = [ {name: "Jay Barnes",
              occupation: "Coffee Shop Manager",
              head: "http://space-for-rent.net/cast-jay-head.png"},
              ... ];
 App.CastRoute = Ember.Route.extend({
   model: function () { return cast; }
});

And then we can consume it in the template.

<script type="text/x-handlebars" id="cast">
    {{#each item in model}}
        <div><div class="head"><img {{bind-attr src=item.head}}></div>
             <div class="cast_name">{{item.name}}</div>
        </div>
    {{/each}}
</script>

That’s Fine for Merlin, but I Have Dynamic Data

I had this same problem with my Exchange service. I needed to hit my web service for some data.

App.IndexRoute = Ember.Route.extend({
   model: function () {
        return Ember.$.getJSON("https://myendpoint/api/rooms");
    };
});

But in all honestly, that takes forEVER because exchange is SLOW. So I just define a ‘loading’ template and ember makes it all better because of it’s internal use of promises to handle the async call to my server. Ember automatically shows this while waiting for my data, then shows the page with actual data.

<script type="text/x-handlebars" id="loading">
<h2>Please wait, Exchange is <em>SLOW</em></h2>
<center><img src="/Content/spinner.gif" alt="please wait"/></center>
</script>

Let’s Be Specific

If I have a url that needs a data portion, like asking for details of a specific room, I can define that in the route map and access the parameters in my model function.

App.router.map(function(){
    this.route("room", {path: "room/:room_name"});
    ...
});
App.RoomRoute = Ember.Router.extend({
    model : function(params){
        return Ember.$.getJSON("https://myendpoint/api/room/" + params.room_name);
    }
});

Is That It?

Nope. That’s not it. Granted, I’ve gotten a bunch of functionality out of those two parts of Ember; Routes and Templates. I’m now picked up on my bootstraps and I can pick my next battles based on my needs. I’ll sum up the learning path I have left for me using these two apps, and more importantly why I need to learn these things.

  • Components – I’ve used these to reduce the duplication in my templates. They can be passed data so I use them to define how I render an Exchange meeting or for the navigation bar for my comics site.
  • Controllers – I’m currently using them to handle some button triggered actions on the Exchange site. they can also be used to compute properties based on the model values or add two way binging to things like text input fields.
  • Models – I don’t know if my current projects have a need for Ember.Data, but I’m going to use it to represent the comic site’s data using fixtures. This will, hopefully, give me the experience to start with a larger data driven application.
  • Testing – When learning a framework, NEVER worry about automated programatic testing until you have a decent understanding of how things are working. THEN add tests. THEN start considering adding new features test-first. Ember has a fairly decent testing story that I want to start exploring. The more work I do in JavaScript, the more I’m going to need to test. While not needed for sites I have here, thin wrappers around data or APIs, I will be writing some sites with far more complex logic.

There is more EmberJs to learn, but I don’t need it yet. But when I do, I’m confident the documentation will be clear. And so far, the code has bee easy to use. This is the first time I’ve enjoyed web development in several years. I think I’m ready to take back the web.

3 Comments

No Comments

3 Trackbacks

Leave a Reply

Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>