Browsing the blog archives for July, 2014.

Getting from Here to There

work safe

Where do we go from here? We begin with the Url. The history of the web is based around the URL and our ability to transition from one url to another. Ember is built around the Url.

You are a Web Developer if you build apps with Urls

- Tom Dale

Every view we want to represent in our application will be represented as a different Url. When we want to show a specific piece of data, we use a different Url. Want to modify how we are showing the screen, then we add data to the Ulr. This will allow us to Deep Link and share specific views and app state with colleagues and coworkers. This is how the Web has worked since the web began. And Below, we see how the Url communicates with Ember to make choices on what to show the browser.

Ember Url Structure

Ember’s Url Structure taken from the presentation mentioned above.

The Router

The router dissects the Url and chooses which Route, Controller, Model, and Template to compose, execute, and use the results for displaying to the screen. By default, you get an ‘index’ route for free. As if I went to http://example.com/, that would be the default index.

Baby-steps to Customization

I can specify just a route named ‘about’ and that will show an ‘about’ template that will use the path http://example.com/about without specifying that path.

App.Router.map(function(){
    this.route("about");
});

A Route With a Different Name, Would It Navigate as Sweet?

Lets say I have a dumb legacy Url (http://example.com/meet-the-team) I need to keep working. Because Urls are important. But I want my internal code to use clear names (about). I can specify the path used in the route mapping.

App.Router.map(function(){
    this.route("about", {path: '/meet-the-team' });
});

My Pokémans, let me show you them.

One more mapping to cover for now, before we start talking about the magic a route actually does. What if we want to show the same page, but vary the data based on part of the path? I have a super awesome collection of Pokémans, let me show you my favorite Squirtle. I keep him at http://www.example.com/pokedex/poke_1. I can specify part of the path to be a dynamic segment. The name of the dynamic segment will show up as a param in the Route code.

App.router.map(function(){
    this.route("pokedex", {path: "/pokedex/:poke_id"});
});

Spent All That Time Defining

It’s neat and all that I’ve just created a route with a dynamic segment. But I need to use that to actually do work. I can create a PokedexRoute and override it’s model creation!

App.PokedexRoute = Ember.Route.extend({
    model: function(params){
        return Ember.$.getJson('api/pokemon/' + params.poke_id);
    }
});

What’s a lifecycle?

There are so many hooks in the route that I can override. I can override the controller creation. I can specify a non-standard template. Oh, that might be fun! This is the BEST pokemans, so he needs a custom template.

App.PokedexRoute = Ember.Route.extend({
    renderTemplate: function(controller, model){
      if(model.name === "Squirtiepie") {
         this.render("pokedex_squirtle");
      } else {
        this.render('pokedex');
      }
    }
});

Odds and Ends

If your code is slow, because for example not tied to anything real and not to name names or anything you query exchange, you can create a template called ‘loading’. Or you an overload the loading behavior.

The same thing with handling errors.

Customizing the Base

You may notice that the Url ember gives you has a hash (#). You can pick the location strategy as one of the following three. If you don’t like the hash, you can use the ‘location’. If you’re running an app out of a page, you can use ‘none’. The ‘hash’ strategy is the default.

App.Router.reopen({
    location: 'history'
});

Transition Overrides

When you edit the Pokedex, you don’t want to update the data until the Pokemaster is finished with her entry and presses the submit button. But what if she clicks on a link to another page? We can intercept the transition and quit!

App.PokedexEditRoute = Ember.Route.extend({
    action: {
	    willTransition: function(transition){
			if(this.controller.get('formHasEdits') &&  confirm("Are you sure you want to throw away your changes?")){
				transition.abort();
			} else {
				return true;
			}
		}
	}
}	
});

We could also validate the input for correctness and prevent a transition if we found it necessary.

Redirecting

Let’s say you load a model and need to decide to redirect because any Pikachu needs to redirected to a list of rats. That jerk gets all the attention anyway.

App.PokedexRoute = Ember.Route.extend({
   afterModel: function(model, transition){
      if(model.get('type') ==='Pikachu'){
        this.transitionTo('rats');
      }
   }
});

You Are Here

The router is all about defining the transitions between your views. In all honesty, the next time I write a desktop application, I may have to write something like this. It’s super easy to manage and override just about any transition. It’s useful, flexible, and the heart and soul of your application.

2 Comments

Rise of the Tetrad

work safe

Ember has about six concepts that once you understand a bit will help you unlock the documentation and figure out how to develop your site. I have written before about not needing to fully understand ember before working on a project, but once you start getting your feet under you and need to branch out. My hope is that by the time you are done reading, you will have a roadmap to the Ember Guides and the Ember APIs.

Rise of the Tetrad

Ember uses naming conventions to tie together the four moving parts of an ember application; the Route Name, the Route, the Controller, and the Template.

The Route Name

When the route is defined like I did below, it is given a name. By default, the path mapped to the route is the same as the route. For example, the route below defines a route named “level1” and maps the url “/level1” to the route of the same name.

Route.map(function(){
 this.route("level1");
 ...
});

The Route

By default we are generating a route named App.Level1Route. If we want to change the behaviors of the route, which we will cover in more depth in a different post, we need to define our Route and provide it with some overrides. A common override is to provide some model data, like below

App.Level1Route = Ember.Route.extend({
 model: function(){
 return Ember.$.getJSON("http://mygame.com/api/level1.json");
 }
});

The Controller

Again by default, we have a controller called App.Level1Controller created for us. But if we want to override its behavior, we just make a new one with the correct name! For example, we can add an action to save the current state back to the server.

App.Level1Controller = Ember.Controller.extend({
 actions: {
 save: function(){
 Ember.$.postJSON("http://mygame.com/api/pause/", model);
 }
 }
});

The Template

We need to show screens for our level. This is done by showing a template. The default template is, of course, named ‘level1’. The template is written in handlebars.

<script type="text/x-handlebars" data-template-name="level1">
  <button {{action 'save'}}>save</button>
  <canvas name="game-level" width="500" height="400">
  </canvas>
</script>

Numbers are tricky. You said there were six, told us about four, but it looks more like only three.

Right. The Route, Controller, and Template are all based off of the Route’s Name. So, four for the price of three. The Other Fourth is the model. I’m just going to skip it for now. The three Ember apps I have written have not yet needed the complexity of an Ember Data model.

The other pieces you will come across are the Components, the views, and Router.

The Router

The router is the part that wires all the components together. We used it to set up our route mapping.

Views

Views let you add behavior to an html tag. You can add behaviors and event handlers to the tag.

Components

Components are an implementation of the W3C Custom Element Spec. They are far more functional than overriding an html tag, they are custom tags backed by a template and code that allow you to build custom controls. If you need a calendar control, start here. Need a tabbed page control? Check out Ember-Components.com for some examples.

Next Steps

Now that we know our way around the major concepts of the Ember framework, we can start to understand them one at a time. Maybe next time we will start with the routes.

No Comments