user2385136
user2385136

Reputation:

Backbone.js Router Matching Optional Parameters

I'm trying to create a backbone router that can match optional parameters.

Consider the following code:

routes: {  
  '/jobs'                                     : 'jobs',
  '/jobs/p:page'                              : 'jobs',
  '/jobs/job/:job_id'                         : 'jobs',
  '/jobs/p:page/job/:job_id'                  : 'jobs'
}

jobs: function(page, job_id){
   // do stuff here ....
}

If I navigate to URL abc.com/#/jobs/p104/ the page parameter will be 104. However, if navigate to abc.com/#/jobs/job/93, the job_id parameter is undefined but the page parameter is 93.

So Backbone's router basically matches the routes hash parameters by order and not by name.

I know the solution would be to use a *splat and split the parameters with regex, but I can't seem to get the regex part to work (my regex is pretty rusty). Can someone please help?

If there's a better solution than using *splat, can someone please share?

Upvotes: 7

Views: 13289

Answers (3)

Scott Weaver
Scott Weaver

Reputation: 7351

try this (single regex, works on all your input formats)

var re = /\/jobs(?:\/p(\d+))?.*?(?:\/(\d+)|$)/;
var matches = 'abc.com/#/jobs/p104/4'.match(re);
var page=false;var job=false;
if (matches != null) {
    var page = matches[1] || false;
    var job = matches[2] || false;
}; 
alert("page:" + page + ",job:" + job)

**matches first the pNNN segment if it is there, and uses a non greedy quantifier with dot . that can eat anything .*? to crawl up the string one by one, so that the second group (just /NNN) will also match if present. the (?: exp ) are non-capturing groups, they group, but they don't "remember" anything.

Upvotes: 2

abraham
abraham

Reputation: 47833

Instead of messing with regexes it would be easier and less error prone just to have a second function. You will probably have to bindAll this in an initialize function for this.jobs to work.

routes: {  
  '/jobs'                                     : 'jobs',
  '/jobs/p:page'                              : 'jobs',
  '/jobs/job/:job_id'                         : 'jobsId',
  '/jobs/p:page/job/:job_id'                  : 'jobs'
},

jobs: function(page, job_id){
   // do stuff here ....
},

jobsId: function(page, job_id){
   this.jobs(undefined, job_id
}

Upvotes: 21

rjz
rjz

Reputation: 16510

If you're going to be doing a lot of these, you might glance at this pattern for wrapping them up tidily. For just these, though, the following regexs ought to do it:

/\/jobs\/p(\d+)/              => /jobs/pXXX
/\/jobs\/p(\d+)\/job\/(\d+)/  => /jobs/pXXX/job/XXX

You can then use String.match with the splats you retrieve to extract the url fragments in question. Using strings in place of a splat variable:

var matches = '/jobs/p18'.match(/\/jobs\/p(\d+)/);
var page = matches[1];

var matches = '/jobs/p4/job/6/'.match(/\/jobs\/p(\d+)\/job\/(\d+)/);
var page = matches[1];
var job = matches[2];

Upvotes: 0

Related Questions