5
\$\begingroup\$

I am building a JS router and would like to have some help doing it. It will work like so:

A list of routes is given with a URL pattern attached in each one.

[
 { url : "/home"},
 { url : "/user/:id"}
]

I want a function that will find the appropriate pattern when we pass it a route URL and will return the object of parameters:

getRouteParams("/home"); // {params: {}}
getRouteParams("/user/42"); // {params: {id: "42"}}
getRouteParams("/contact"); // null

I tried to do something with some parts of code I have found on the web and here is what I ended up with:

var routes = [
 { url : "/home"},
 { url : "/user/:id"}
];
function getRouteParams(url) {
 var argsVal = null;
 var x = 0;
 var result = {};
 for(; routes.length; x++){
 var routeMatcher = new RegExp(routes[x].url.replace(/(:\w+)/g, '([\\w-]+)'));
 argsVal = url.match(routeMatcher);
 if(argsVal) {
 argsVal.shift();
 result.params = makeObj(argsVal, routes[x].url);
 break;
 }
 }
 return result;
 function makeObj(vals, url) {
 var routeParts = url.split('/');
 var options = {};
 for(var i=0, j=0; i<routeParts.length; i++) {
 if(routeParts[i].indexOf(":") !== -1) {
 options[routeParts[i].slice(1)] = vals[j++];
 }
 }
 return options;
 }
}
console.log(getRouteParams("/home")); // {params: {}}
console.log(getRouteParams("/user/42")); // {params: {id: "42"}}
console.log(getRouteParams("/contact")); // null)

This is a bit more sophisticated but the idea is there. Could someone help me improve on what I did?

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jan 22, 2016 at 13:58
\$\endgroup\$
3
  • 1
    \$\begingroup\$ I edited my post, sorry for that, this is my first post... \$\endgroup\$ Commented Jan 22, 2016 at 14:25
  • 2
    \$\begingroup\$ Welcome to Code Review! I have rolled back the last edit. Please see what you may and may not do after receiving answers . \$\endgroup\$ Commented Jan 25, 2016 at 9:20
  • \$\begingroup\$ I posted a self response instead, hope this is what was expected... \$\endgroup\$ Commented Jan 25, 2016 at 9:45

2 Answers 2

3
\$\begingroup\$

Your algorithm seems to be working.

Here is the few things I would do to improve it:

// The routes should be a parameter of the function
function getParams(routes, url) {
 var params = null;
 // Depending on the targeted browser, you could use the native forEach method
 routes.forEach(function (route) {
 // I personally prefer to use methods in here
 if (params === null && routeMatch(route.url, url)) {
 params = computeParams(route.url, url);
 }
 });
 return { params: params };
 function routeMatch(route, url) {
 // You don't need to use `new RegExp`
 // I've added ^ and $ to be sure that it would be working with nested routes
 var matcher = '^' + route.replace(/(:\w+)/g, '([\\w-]+)') + '$';
 return url.match(matcher);
 }
 function computeParams(route, url) {
 var routeParts = route.split('/');
 var urlParts = url.split('/');
 var options = {};
 for (var i = 0, nbOfParts = routeParts.length; i < nbOfParts; i++) {
 // I check that the url part exists
 // and use the binary operator ~ that simplifies the `indexOf` method
 if (urlParts[i] && ~routeParts[i].indexOf(':')) {
 options[routeParts[i].slice(1)] = urlParts[i];
 }
 }
 return options;
 }
}
var routes = [ { url: '/home' }, { url: '/user/:id' }, { url: '/user/:id/post/:postId' }, { url: '/user/:id/post/:postId/comment/:cId' } ];
printResult(getParams(routes, "/home").params, {});
printResult(getParams(routes, "/user/42").params, { id: '42' });
printResult(getParams(routes, "/user/42/post/52").params, { id: '42', postId: '52' });
printResult(getParams(routes, "/user/42/post/52/").params, null);
printResult(getParams(routes, "/user/42/post/52/comment/").params, null);
printResult(getParams(routes, "/user/42/post/52/comment/yolo-22").params, { id: '42', postId: '52', cId: 'yolo-22' });
printResult(getParams(routes, "/contact").params, {});
function printResult(result, expected) {
 console.log('expected: ', expected, 'result: ', result);
}

That's all I can think of.

Vogel612
25.5k7 gold badges59 silver badges141 bronze badges
answered Jan 23, 2016 at 9:28
\$\endgroup\$
1
  • \$\begingroup\$ Thank you!! I'll study your answere and try to enhance what I've made before your post. \$\endgroup\$ Commented Jan 25, 2016 at 9:14
0
\$\begingroup\$

I improved my code in the meanwhile, before looking at what you suggested. I'll study how I could merge that with yours.

Here is my actual improved code :

var routes = [
 {url: "/users/:uid/pictures/:avatar"},
 {url: "/users/:uid"},
 {url: "/home"}
];
function getRouteParams(url) {
 var argsVal,
 argsNames,
 params = {};
 for(var x = 0; x < routes.length; x++){
 var currRoute = routes[x].url;
 var routeMatcher = new RegExp(currRoute.replace(/(:\w+)/g, '([\\w-]+)'));
 argsVal = url.match(routeMatcher);
 if(argsVal) {
 argsVal.shift();
 argsNames = currRoute.match(/(:\w+)/g);
 if(argsNames) {
 for(var y = 0; y < argsNames.length; y++){
 params[argsNames[y].slice(1)] = argsVal[y];
 }
 }
 return {
 params : params
 };
 }
 }
 return null;
}
console.log(getRouteParams("/users/1024/pictures/ok")); // {params:{uid:"1024", avatar: "ok"}
console.log(getRouteParams("/users/zezen")); // {params: {uid: "zezen"}}
console.log(getRouteParams("/home")); // {params: {}}
console.log(getRouteParams("/zezen")); // null
community wiki

\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.