patternjavascriptMinor
Simple JavaScript router with params
Viewed 0 times
paramssimplejavascriptwithrouter
Problem
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.
I want a function that will find the appropriate pattern when we pass it a route URL and will return the object of parameters:
I tried to do something with some parts of code I have found on the web and here is what I ended up with:
This is a bit more sophisticated but the idea is there. Could someone help me improve on what I did?
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"); // nullI 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?
Solution
Your algorithm seems to be working.
Here is the few things I would do to improve it:
That's all I can think of.
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-]+)') + '
That's all I can think of.;
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.
Code Snippets
// 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);
}Context
StackExchange Code Review Q#117596, answer score: 3
Revisions (0)
No revisions yet.