Results 1 to 8 of 8

Thread: Using router with optional, named URL arguments

Hybrid View

Previous Post Previous Post   Next Post Next Post
  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,556
    Vote Rating
    1272
      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! Checkout the CODE tag!

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

  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
  •