Previously we looked at a very simple sample application
that uses responders to manage application state. Now that our responder-fu is strong, we can take a further step of using SproutCore routes
to manage history via states.
The Underlying Technology
In particular, these single-page applications use the
Registering a route
In order to make use of routes in SproutCore, you need to register any route changes you want to watch for. This is done by providing a route string that is matched against the browser location, along with a target object and method you want called on that object. Since route changes will often coincide with state changes, it makes sense to use responders to handle them. The Routes sample application has a superstate,
Routes.states.root, that all of the other states are substates of, so this is the responder that is registered:
Now that this route has been registered, any time the browser location hash changes the
route method in
Routes.states.root will be called, with a hash that has a
number property consisting of everything to the right of the ‘#’ character in the URL. SproutCore will now monitor the location hash for changes that match this route, either in an event-based way for browsers that support it, or by using a timer.
Setting your location
You set a route in SproutCore by setting the
location property for SC.routes, for instance
SC.routes.set('location', 'here'). In the Routes sample app, when a change in the location hash occurs and the
route method in
SC.states.root is called, that method simply passes the
property that was captured to the
go method, the location is set to the route number that is passed in, and as a nice touch the browser title is also updated to reflect the current route number. Finally, the state is set with Routes.makeFirstResponder.
Following route and state changes
Now that they key players have been identified, it may be useful to follow the flow of events when actually interacting with the app. Assume we’re running sproutcore-samples at http://localhost:4020.
Immediately upon entering the app by browsing to http://localhost:4020/routes, the route that was set by
SC.routes.set above will notice the initial URL as a “change”, call the
route method in
SC.states.route, and in turn enter the
go method. Since the location hash starts off empty, the following code in
go will default to the one route, and then set the location hash, browser title and state to one:
So the URL that we intially see once the app is done loading is http://localhost:4020/routes#one. Now let’s say we click on another button, three for instance. Looking in resources/main_page.js we can see that all of the buttons have
go as their action:
Currently the state is Routes.states.one, however when we look there we see that this state doesn’t define the
go method itself. Instead, all of the substates simply define
Routes.states.root as the
This is what makes these substates of
Routes.states.root, so the
go call won’t be found in the first responder, causing it to go up the chain to
Routes.states.root. This will in turn change the current URL to http://localhost:4020/routes#three, update the page title and set the state to three. Importantly, each time the current route is changed, those changes are reflected in the browser history. We could continue clicking buttons like this as long as we’d like, accumulating a history of being in the different locations that each button correspond to.
If we next hit the back button in our browser, that will change the browser URL back to http://localhost:4020/routes#one. Because of the route we added, this will trigger calling
go in the root responder, and in turn the page title and state being updated to one.
The Routes sample app provides a simple, albeit contrived, example of how routes and states allow us to use history in our apps. In order to apply this to a real app, you would need to consider what states in your app you’d like to make available in the browser history, and how you would accomplish transitioning to those states from essentially any other state in your app. I only know of one real app that uses responders and routes for history management, SproutCore Tests. There are some interesting nuances to how it works with routes, so it’s certainly worth a look if you have the time.