Threaded View

  1. #1
    Sencha User
    Join Date
    Mar 2007
    Posts
    411
    Vote Rating
    17
    jweber will become famous soon enough

      2  

    Default Using router with optional, named URL arguments

    Using router with optional, named URL arguments


    I thought I would share this, in case anyone else needs it. I wanted to use Sencha's routing, but with URLs like #users/johndoe?foo=one&bar=two, so that certain arguments could be optional. This "query string" is separate from the actual query string, since it follows the hash mark. But it's in the same format, so it's easy to read.

    Here's what I did:

    Code:
    Ext.define('Ext.app.QueryRouter', {
    	extend: 'Ext.app.Router',
    	requires: ['Ext.app.QueryRoute'],
    
    	connect: function(url, params) {
    		params = Ext.apply({url: url}, params || {}, this.getDefaults());
    		var route = Ext.create('Ext.app.QueryRoute', params);
    
    		this.getRoutes().push(route);
    
    		return route;
    	}
    });
    
    Ext.define('Ext.app.QueryRoute', {
    	extend: 'Ext.app.Route',
    
    	initialize: function() {
    		this.callParent(arguments);
    		this.parseQueryRegex = new RegExp("([^?=&]+)(?:=([^&]*))?", "g");
    	},
    
    	recognize: function(url) {
    		var action = this.callParent(arguments);
    		if (action) {
    			var queryStr = action.args.pop(),
    				query = {},
    				match;
    			if (queryStr[0] === "?") {
    				queryStr = queryStr.slice(1);
    				while ((match = this.parseQueryRegex.exec(queryStr)) !== null) {
    					query[decodeURIComponent(match[1])] = (match[2] === undefined ? undefined : decodeURIComponent(match[2]));
    				}
    			}
    			action.args.unshift(query);
    		}
    		return action;
    	},
    
    	createMatcherRegex: function(url) {
    		var paramsInMatchString = this.paramsInMatchString,
    			length = paramsInMatchString.length,
    			i, cond, matcher;
    
    		for (i = 0; i < length; i++) {
    			cond    = this.getConditions()[paramsInMatchString[i]];
    			matcher = Ext.util.Format.format("({0})", cond || "[%a-zA-Z0-9\-\\_\\s,]+");
    
    			url = url.replace(new RegExp(paramsInMatchString[i]), matcher);
    		}
    
    		return new RegExp("^" + url + "((?:\\?.*?)?)$");
    	}
    });
    Then in my app.js:

    Code:
    Ext.application({
    	router: {
    		xclass: 'Ext.app.QueryRouter'
    	}
    Now in my controller classes, I can continue to use Sencha's routing as usual. But the new first argument passed to the action functions will be an object, mapping argument names to their values. For example:

    Code:
    {
    	foo: "one",
    	bar: "two"
    }
    The rest of the arguments will be the same as before. You can leave off the "query string" entirely, and you'll be passed an empty object as the first argument.
    Last edited by jweber; 30 Apr 2012 at 10:47 AM. Reason: change argument order