Sencha Inc. | HTML5 Apps

Implementing Routes with Sencha Architect

Published Jun 07, 2012 | Jason Johnston | Tutorial | Easy
Last Updated Jun 20, 2012

This Tutorial is most relevant to Sencha Architect, 2.x.

Two typical shortcomings of single-page Web apps are incorrect behavior of the browser’s “back” button, and the inability to link directly to deep content. Thankfully, the Sencha Touch 2 MVC framework includes powerful support for history tracking and deep linking, commonly referred to as “routes”.

In this tutorial, we will demonstrate how to use Sencha Architect to implement routes in a Sencha Touch 2 application. It assumes that you have a basic working knowledge of how to use Sencha Architect; see our documentation guides to familiarize yourself. You should also be familiar with the basics of the Sencha Touch MVC framework.

If you wish you can download the completed project file.


We’re going to start with something extremely simple to demonstrate the basic routing concepts. We’ll create a bare-bones app consisting of a single Tab Panel with three tabs; we’ll then add a route, so the initially selected tab can be controlled by the URL.

Let’s begin by creating our views. Drag a Tab Panel from the toolbox onto the empty canvas; it will automatically create three tabs for you. Select the first tab, change its title config to “Home”, give it an itemId config of “home”, and set its html config to “Welcome!”. Select the second tab, change its title config to “About”, give it an itemId of “about”, and set its html config to “We are awesome.”. Select the third tab, change its title to “Contact”, give it an itemId of “contact”, and set its html config to “Just holler!”.

Tab Panel View Components

Save and preview your project; you’ll see the tabs and be able to switch between them, but each time you reload the page it will always display the Home tab by default. Let’s fix that.

Creating a Route

Add a controller to your project by clicking the “+” button above the Project Inspector and selecting “Controller”. Add a Controller Reference to it by clicking the “+” button next to the References item in the config pane, giving it a name of “main”, and a selector of “>tabpanel” (this will allow us to reference the main Tab Panel view component later on by calling the getMain() controller method).

Now, add a Controller Route to the controller by clicking the “+” button next to the Routes item in the config pane. Select the route, set its url config to “tab/:tabId”, and its action to “gotoTab”. Double-click the controller route in the inspector to enter code editing mode, and add the following code:

var tabPanel = this.getMain(), //uses our Controller Reference
    tabCmp = tabPanel.child('#' + tabId);
tabPanel.setActiveItem(tabCmp || 0);

Route Configuration

Let’s examine what we’ve done. The route’s url config defines the pattern of the URL’s fragment (the part after the “#”) that will trigger the route. The action defines the name of the function that will be executed when the route matches.

Within the url, the “:tabId” portion is a variable parameter; it will match any alphanumeric value, and that value will be passed as an argument to the action function.

That action function which we have named “gotoTab” will attempt to find the tab with the itemId matching the “:tabId” route parameter, and set it as the tab panel’s active tab.

Therefore, when the user comes to your app using the URL “app.html#tab/about”, the fragment “tab/about” will match our route’s “tab/:tabId” url pattern, causing the gotoTab function to be called with the value “about” passed in as its tabId argument. Let’s try it: save and preview your project, and add the fragment “#tab/about” onto the end of the URL in the browser. You’ll see that the About tab is now selected by default.

Syncing To User Navigation

Our tabs are now addressable from fragments in the URL, but the user has to somehow know that full URL to be able to use it. What we really need is for the application to update the URL to the correct route fragment while the user navigates, so it always matches the app’s current state. To do this, we will listen for tab change events and update the URL using the application’s History object.

Drag a Controller Action from the toolbox onto the controller. Set its controlQuery config to “main” (once again, this uses our “main” Controller Reference), select “Ext.tab.Panel” for the targetType, and then choose “activeitemchange” for the name config. Double-click the controller action to enter code editing mode, and add the following code:

this.getApplication().getHistory().add(new Ext.app.Action({
    url: 'tab/' + value.getItemId()
}), true);

The controller now listens for when the user changes the active tab, and it pushes that tab’s corresponding route URL onto the app’s global history stack. The url property of the Ext.app.Action is set to the correct route fragment. The final true argument to the add method makes it silent, preventing the controller from executing this route immediately, and thereby avoiding an infinite loop.

Give it a try; save and preview your project, and switch between tabs in the UI, watching the URL change to match. You’ll see you are now able to:

  • Reload the page at any point and have the selected tab be maintained,
  • Copy-paste the current URL at any point, send it to a friend, and have the proper tab be selected, and
  • Navigate between tabs using the browser’s standard Back/Forward buttons.

Route In Browser

Advanced Routes

Most routes are as simple as that, but there are some more advanced route configuration options that you might need in some cases.

Parameter Conditions

By default, a route parameter (the bit with the colon like our “:tabId”) accepts a sequence of characters including letters, numbers, dashes, underscores, and percent symbols. Sometimes, it’s useful to customize the characters allowed in the sequence. As an example, let’s limit our “:tabId” parameter to only accept letters.

Select the route in the Project Inspector and find the “Conditions” item in the Config Pane; click its “+” button to add a new condition. Select the newly added condition. For its param config, choose the “tabId” parameter from the dropdown; if your route has more than one parameter they’ll all appear in the list. Set its condition config to “[a-zA-Z]+”.

Now if you save and preview the project, the route will only execute if the parameter contains only letters; trying to access a URL that does not match, like “app.html#tab/12345”, will not match.

Filtering

Often, your application requires more complex setup or validation logic before a route is executed, for example loading extra classes, populating data stores or performing user authentication. These cases can be handled by adding a Before Filter for your route.

As an example, let’s add a filter that only allows the route to execute when the current time is an odd-numbered minute. Of course, this is a silly thing to do, but you could replace this check with a more useful one, such as calling out to a user authentication service.

Drag a Controller Before Filter from the toolbox onto the controller. Click its routeAction config and notice that its dropdown is populated with the “gotoTab” action name from our route; if there were more routes then they would also appear. Select “gotoTab”. Set its fn config to “checkMinute”.

Now double-click the Before Filter to enter code editing mode. Insert the following code:

if ((new Date()).getMinutes() % 2) {
    action.resume();
} else {
    Ext.Msg.alert('Oops,', 'You can only link to this tab during' + 
        ' odd-numbered minutes! Why? Great question.');
}

This code checks if the current minute is an odd number, and if so calls action.resume() which allows the route to continue executing. (Note that this can be called asynchronously, such as from the result of an external authentication Ajax call.)

Give it a try; save and preview the project using one of the tab’s route URLs, and you’ll see it will work when the minute is odd but show the alert message when the minute is even.


Now you know how to implement routes in your Sencha Touch app using Architect. While the sample project we just created is extremely simplistic, routes are implemented using these exact same concepts in projects of any complexity.

If you run into issues, please visit the Sencha Architect Forums and/or the Sencha Touch Forums.

Share this post:
Leave a reply

Written by Jason Johnston

Commenting is not available in this channel entry.