1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
---
layout: post
title: Your Ember app is a click away from home
tags: [ ember, development ]
published: true
---
I've been having some time to explore Ember.js lately and I wanted to learn by
doing instead of just reading about it. So bear with me as this might probably
require some updating in the future. This is a result of trial and error and I
thought of making the Ember learning curve a little easier and share this tip.
So I've been trying to build a simple application that manages pictures. I
started the good ol' fashioned way of manually calling all the scripts and
declaring all the templates from the index page, for argument's sake. I would
much rather have something like
[Iridium](http://github.com/radiumsoftware/iridium) to help with my development
process but I had faced some trouble with it before.
My first step: list of pictures
-------------------------------
The first thing that came to my mind was to have a list of pictures and allow
the user to add a new one by clicking on a link that would transition to
something like `/pictures/new`. In the pictures list template I would have
something like:
{% highlight html %}
<h2>Images</h2>
{%raw%}{{#each image in controller}}
<li>{{image.title}}</li>
{{/each}}
<p>
<a {{action newImage href="true"}}>New image</a>
</p>
{%endraw%}
{% endhighlight %}
The link in the paragraph goes to the route transition in "root". Let me give
you the router so you can better understand what I'm saying:
{% highlight javascript %}
Exhibit.Router = Ember.Router.extend({
root: Ember.Route.extend({
, index: Ember.Route.extend({
route: "/"
, connectOutlets: function(router, context) {
router.get("applicationController").connectOutlet("images", Exhibit.Image.all());
}
, newImage: Ember.Route.transitionTo("newImage")
})
, newImage: Ember.Route.extend({
// ...
})
})
});
{% endhighlight %}
Inside the `index` route, the `newImage` path points to the `newImage` route
which will print a form.
The challenge: Going back home
------------------------------
At this point in time, I was curious as to the possibility of aborting the
process of creating a new image and simply going back home and start over. As I
was learning, I realized that actions in the templates point to routes in the
router as a way to acknowledge an application state change. I faced the
challenge of wanting to leave the form and go back and not being able to
do it.
I recalled that actions should be defined in the state (the route) the
application is in. Clicking on the `newImage` link transitions my app to the
`root.newImage` state. So I thought of doing something like this in the router:
{% highlight javascript %}
Exhibit.Router = Ember.Router.extend({
root: Ember.Route.extend({
, index: Ember.Route.extend({
// ...
})
, newImage: Ember.Route.extend({
route: "/new"
, connectOutlets: function(router, context) {
// connect the outlet
})
===> , goHome: Ember.Route.transitionTo("root.index")
})
})
});
{% endhighlight %}
This looks rather trivial and probably won't make the point alone. What I
thought at the time when I wrote this was _should I really need to write this
transition in every single route?_ After all, going back home should be
possible for every action, every state in the app.
The solution: Use the state machine
-----------------------------------
After some trial and error, I ended up with this:
{% highlight javascript %}
Exhibit.Router = Ember.Router.extend({
root: Ember.Route.extend({
=> goHome : Ember.Route.transitionTo("root.index")
, index : Ember.Route.extend({ /* ... */ })
, newImage : Ember.Route.extend({ /* ... */ })
})
});
{% endhighlight %}
Since the router is a state machine, when defining the `root` route, I'm able
to add state changes there that will be inherited for every sibling state in
that tree. Both `index` and `newImage` and all the routes that are defined in
`root` will have this state change available.
This was a finding for me as I have never grasped the concept of state machines
like this.
|