In my last post, we explored the new routing functionality that has been incorporated in Ext JS 5. I had a lot of great feedback and discussions come from that (thanks!), so I thought I’d add a few more notes about some of the routing functionality that I didn’t discuss in the last post. So without further jabbering, let’s dive in.

Route Conditions

One nice feature of routing in Ext JS 5 is that not only can you add a before handler to the route execution, but you can also filter routes which will be matched based on a regex string.

For example, let’s consider our users/:id route from the last post:

routes: {
    ...
    'users/:id': {
        action: 'onUserDetail',
        before: 'onBeforeUserDetail'
    }
}

As written, this route will match any hash in this form, regardless of what actual value is passed for our “id” placeholder. What this means is that if someone gets clever and starts to try to manually hack our hash with some value other than what comes naturally from our application, our before handler is still going to fire on the hacked value, and whatever code is in that handler will execute.

Obviously, we could put some error/hack handling in our before handler, but we can also use the conditions config to automatically weed out obviously incorrect patters.

In this example, let’s assume that all of our user ids are numeric, so we want to automatically ignore any hashes that match our route pattern, but have an “id” value that’s not numeric.

routes: {
    ...
    'users/:id': {
        action: 'onUserDetail',
        before: 'onBeforeUserDetail',
        conditions : {
            ':id' : '([0-9]+)'
        }
    }
}

This is pretty straightforward. Using the conditions config, we supply a regex string for our id placeholder that will instruct the Router to not process this route if the hash does not match the route + condition, but instead trigger the unmatchedroute event (more below).

Now we come to an important point of consideration. Obviously, you could use the before handler to accomplish the same thing. That is, you could inspect the incoming parameters from the route, run any kinds of checks against them that you want to, and then choose to resume or stop the route action based on whatever your application’s logic determines is needed to be done.

With conditions, you have no such opportunity. If the condition fails the incoming hash, the route’s action simply doesn’t get executed. All that will happen is that the Router’s generic unmatchedroute event will get fired, passing only the hash that was unsuccessfully matched.

What would be nice is if each route could define something like a conditionfail handler. This would be a handler that could be fired when a route’s base pattern is matched (e.g., users/:id) but is proactively failed because of the route’s configured conditions. I think this would be useful because it would allow for much more precise handling of unmatched routes. Instead of having to try to handle all unmatched routes in a single handler (which is currently how it works), the per-route configuration of unmatched route handlers would give much more granular context for dealing with the unmatched route however the particular instance dictates. Just a thought! :)

Unmatched Routes

I’ve mentioned it above, but the new Router also includes the ability to deal with any unmatched routes. Whenever an unmatched route is detected (e.g., a hash matching a pattern that simply isn’t defined, or a hash that fails an existing route’s condition), the unmatchedroute event is fired on base application instance. You can easily set up a listener for this like so:

In Application.js

listen: {
   controller: {
      '#': {
         unmatchedroute: 'onUnmatchedRoute'
      }
   }
},
onUnmatchedRoute: function( hash ) {
   alert( 'Sorry, the ' + hash + ' route is not correct' );
}

Multiple Routes in a Single Hash

If you have a need within your application, the new Ext JS 5 Router also supports the execution of routes from the same hash. You can specify multiple routes in a single hash simply by concatenating each desired route with a pipe (|). This can be overriden by setting the multipleToken property of Ext.app.route.Router.

So this:

users/1234 | info (no spaces)

Would match and execute the actions for the following routes:

'users/:id'
'info'

The important thing to keep in mind about multiple routes is that they are completely segregated from each other. They do fire in order, but their execution does not depend on the resumption or cancellation of each other. So if my first route fails or is programmatically stopped, it will have no effect on subsequent routes.

In my mind, multiple routes would typically have some relationship to one another, so I’ve not been able to come up with a good use case for this. Also, the API for dealing with multiple routes feels a bit incomplete. The idea is that the multiple routes *should* be independent from one another, but there is not really a simple way (that I know of) to append or remove routes from the hash. So even though you *should* be treating multiple routes as independent things, they ultimately have to be created together as part of whatever action is actually creating the hash.

I would propose the following additions to controllers to help deal with this:

addTokenPart (part, override): Preserves current hash and appends new “part” using multipleToken setting. If override is true, does search for “part” in existing token, removes it from existing location before appending to the end; if false, does not append if part already exists in token

removeTokenPart(part): Removes token part from existing token

Conclusion

There’s more that could be said for Routing in Ext JS 5, but I think it’s time to move on. I’m going to be looking at View Controllers next, hooray! :)