Results 1 to 7 of 7

Thread: Using router with optional, named URL arguments

  1. #1
    Sencha User
    Join Date
    Mar 2007
    Posts
    443
    Vote Rating
    18
      2  

    Default 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

  2. #2
    Sencha - Sr Software Engineer mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    39,326
    Vote Rating
    1297
      0  

    Default

    So it's basically like a data payload type of thing. How does this look in the route handler in the controller?
    Mitchell Simoens @LikelyMitch
    Sencha Inc, Senior Software Engineer
    ________________
    Learn BBCode and use it!

    Check out my GitHub, lots of nice things for Ext JS 4 and Sencha Touch 2
    https://github.com/mitchellsimoens

    Think my support is good? Get more personalized support via a support subscription. https://www.sencha.com/store/

    Need more help with your app? Hire Sencha Services services@sencha.com

    Want to learn Sencha Touch 2? Check out Sencha Touch in Action that is in print!

    When posting code, please use BBCode's CODE tags.

  3. #3
    Sencha User
    Join Date
    Mar 2007
    Posts
    443
    Vote Rating
    18
      0  

    Default

    With the sample URL above, if your route was 'users/:username', your controller function might look like:
    Code:
    routeUser: function(query, username) {
       console.log(query.foo, query.bar, username);
       # 'one', 'two', 'johndoe'
    }

  4. #4
    Sencha User
    Join Date
    Sep 2012
    Location
    Ljubljana
    Posts
    23
    Vote Rating
    0
      0  

    Default

    Thank you so much jweber.

  5. #5
    Sencha User
    Join Date
    Jul 2012
    Posts
    9
    Vote Rating
    1
      0  

    Default

    Thanks jweber!

    I almost have this working in Architect.
    In Architect how do I change up the controller route action so it can take up the query object?

    Code:
    routes: {
                'tab/:tabId': 'gotoTab'}
    
    
    gotoTab: function(query, tabId) {}

  6. #6
    Sencha User
    Join Date
    Mar 2007
    Posts
    443
    Vote Rating
    18
      0  

    Default

    Sorry, I haven't really used Architect enough to help there.

  7. #7
    Sencha Premium Member
    Join Date
    May 2012
    Posts
    3
    Vote Rating
    0
      0  

    Default

    Thank you very much! It works very well!

  8. #8
    Sencha User
    Join Date
    Mar 2014
    Posts
    0
    Vote Rating
    0
      0  

    Default I just override Router

    Code:
    Ext.define('Mobile.overrides.app.Route', {
        override: 'Ext.app.Route',
    
    
        /**
         * @inheritdoc
         */
        recognize: function(url) {
            if (!this.getInitialized()) {
                this.initialize();
            }
    
    
            if (this.recognizes(url)) {
                return {
                    controller: this.getController(),
                    action    : this.getAction(),
                    url       : url,
                    args      : [this.matchesFor(url)]
                };
            }
        }
    });
    In controller i receive param "args" with object

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •