I got great reception from my original post about managing state with AngularJS’s ui-router (ui-router on github,) but some feedback as well. Primarily, there was an ask for a full example (rather than the JSFiddle which seems to break a couple of times a week.) Since the library has matured and if I’m going to create a repo version of this then I’m going to start with yeoman, I decided to write a new post with current versions and an application base generated by yeoman.
If you just can’t wait for the example repo, here it is.
What I wrote before is largely still applicable, so take a look at my original take for a full description.
The gist of the argument, is that routes make sense for discrete endpoints, and states make sense for application composition. If every page was essentially unique, then routes would be sufficient, but in a modern single page web app there are fewer concrete pages and more updates to the application’s screen composition.
Managing your application with states facilitates this way of thinking.
You can get it up and running by cloning a copy and serving it up with grunt:
git clone https://github.com/benschw/ui-router-demo.git cd ui-router-demo bower install npm install grunt serve
If you don’t have any of the dependencies (node, npm, bower, grunt) there are install instructions in the repo README.
grunt serve will pop up a node webserver running on localhost:9000, so you can head there now to check out the application (actually, grunt probably opened a browser for you.) If you aren’t following along at home, you can just take a look at the hosted version and compare against the source code.
Essentially this is a fake webapp with a home page and a settings section. The home page is pretty straight forward and would have made sense to be implemented with routes, but the settings section illustrates the composition problem I outlined above.
This isn’t a “details page.” It’s a web app with a top nav and footer, containing a settings section with “details” selected as the primary focus.
With ui-router I can model this composition as states and if I want to switch to “quotes,” I only need to specify how to re-render that small portion of the page.
The root application is setting up the header, footer, and a container. It does this by registering a root “app” state which supplies a template for the header and footer, and leaves the main container empty.
The home module is just a single state that fills the container with the contents of a container.
This is the meat of our demo, so I’ll dig a little deeper.
The settings module sets up an abstract settings state which adds the
/settings namespace to the url, and defines a
SettingsController which will set user data on the current
$scope. This state also sets up the settings section nav and defines where the primary-focus content will go (its default view.)
There are two submodules here too: details and quotes. For such a trivial example, these could have been part of the settings module (but still constitute unique states), but I wanted to abstract them out to show how you could organize a more complex settings section.
These states piggyback on the
app.settings state to supply content for the abstract settings’ default ui-view. They also leverage the
SettingsController defined in the settings module (since both states show a different view of the same user data resource.)
And there you have it!
ui-router allows you to implement your app more naturally: as a composition of views. No longer do you need to recast how your app is logically structured into a hierarchy or set of unique pages with shared content.