Tutorial: Onsen UI with ui-router

AngularUI Router is perhaps one of the most used modules out there for AngularJS that allows you to organize the parts of your interface into a state machine. Onsen UI doesn’t use URL routing but navigates from one page to another programmatically using the custom elements. However, since in ui-router we can define state transitions and not only URL routes we are able to combine Onsen UI and ui-router in the same app. Learn here how to do it.

Routing in Onsen UI

Onsen UI uses its own route system and was not meant to be used with an external router, but definitely it is compatible with a router such as ui-router. Due to this reason we have to mention that there is not only one way to integrate Onsen UI with ui-router. Here we will explain a basic solution to combine them both that is likely to be enough in most cases. However, if you already have some experience with ui-router probably you can find a way that fits your needs better.

In this tutorial, we will combine three different Onsen UI patterns in order to make it useful for everyone. The main element of our app will be the Tabbar pattern and it will have two child tabs: a Navigator in the first one (MasterDetail) and a Sliding Menu in the second. In addition, since this routing is based on states we will be able to make a transition to a deep route in the Navigator from, for example, the main page of the Sliding Menu.

Looks like a normal Onsen UI app but it really uses ui-router for the state transitions behind the scenes. And the good news is that it is not hard at all once you understand the basic rules.

The layout

In this example we include all the dependencies from CDNs but you can download them locally with Bower or directly from their web pages. We will have two main states for the two tabs called “navigator” and “sliding”. The first one will have a child state called “navigator.master” and a grandchild state called “navigator.master.detail”. Similarly, “sliding” state will have three childs, one per sub-state: “sliding.main”, “sliding.page1” and “sliding.page2”. After setting up our index.html with the needed dependencies we include the main elements of our app in the body:

Here we have a Tabbar as the parent element of our project and two templates with a Navigator and a SlidingMenu. Notice that we are not setting the main page of any element, not even telling the Tabbar that the Navigator and the SlidingMenu are its childs yet. We will connect them later using ui-router.

Note: This example tries to show how to do everything with ui-router. However, you may want to keep using Onsen UI attributes such as Navigator’s page or SlidingMenu’s main-page to link views instead of doing it manually with ui-router.

The ui-sref attribute substitute the normal page attribute in an Onsen UI tab. It does not work exactly in the same way since ui-sref just links to a different state and not to the page itself, but it will do the trick. We will show how to define those states soon.

Now we can create all the HTML pages we want to use in the corresponding folder. Just remember to dont use any function like myNavigator.pushPage( … ), myMenu.setMainPage( … ) or myTabbar.setActiveTab( … ). Use ui-router statements and the name of the states that we mentioned before instead. For example, let’s see how to do it in master.html (the list part of MasterDetail example):

As you can see there, we have a normal Onsen UI page with its own AngularJS controller (in js/controllers.js). The only difference is that, instead of pushing a page with ng-click="myNavigator.pushPage('detail.html', {index: $index})", we pass the index parameter to a ui-router state: ui-sref="navigator.master.detail({index: $index})". The rest of the pages are not more complex than this one, so you can check the code on Github.

Apart from that, we have to be careful if we need an <ons-back-button> in our pages since we cannot change its inner behavior. Instead, we can just use the back button style manually and point it to the state where we want to move with ui-sref. Usually it will be ui-sref="^" since we want to move to the parent state:

The states

Let’s check now how to configure ui-router to make it work together with Onsen UI:

With $urlRouterProvider.otherwise('/master'); we establish a default route for our app. Therefore, when we try to input an inexistent URL/state the app will show the MasterDetail example. This also works as the index/landing page since we will not define any state for the route /.

Finally, we have the most awaited part, the ui-router states for Onsen UI pages:

Those are the states for the MasterDetail example. The very first state is called “navigator” but notice that it is an abstract state. It only provides some functionality and an optional URL prefix. In this state we are setting up the actual Navigator and linking it to the first tab of our Tabbar. The ui-router‘s resolve property will wait until everything is finished so we ensure that the state won’t change without a working Navigator. The truth is that we could combine “navigator” and “navigator.master” states together, but it is more readable in this way.

In the next states we have to play with onEnter and onExit properties in order to update the Navigator with resetToPage(), pushPage() and popPage(). As mentioned before, we can also pass parameters to states by using URLs like '/master/detail/:index' and the $stateParams service.

Similarly, the states for Sliding Menu will be as follows:

The first “sliding” state is similar to “navigator” state. It simply sets up the SlidingMenu as an abstract state. This time “main”, “page1” and “page2” will be all siblings and direct childs of the Sliding Menu. Now we just need to map every ui-sref to myMenu.setMainPage( … ), and we use onEnter property again for this purpose. It would be also possible to have a “dynamic state” that receives the page name as a parameter (with $stateParams) and moves to it with setMainPage( 'page' ) so we don’t need a new state for every simple page that we have.

Conclusion

As mentioned before, this was just one way to integrate Onsen UI with ui-router. Have you found this post useful or do you have any suggestion related to ui-router and Onsen UI? Please leave your impressions in the comments. Since ui-router is a great module and we would like to support it better, some updates to Onsen UI could come in next versions related to this topic. Stay tuned!