Skip to content

Commit a6ca783

Browse files
committed
Parse querystrings, if passed. Fixes #149.
1 parent 25dee39 commit a6ca783

File tree

5 files changed

+52
-6
lines changed

5 files changed

+52
-6
lines changed

lib/RouteRenderingMixin.js

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ var assign = Object.assign || require('object.assign');
1111
var RouteRenderingMixin = {
1212

1313
renderRouteHandler: function(props) {
14+
if (!this.state.match.route) {
15+
throw new Error("React-router-component: No route matched! Did you define a NotFound route?");
16+
}
1417
var handler = this.state.handler;
1518
props = assign({ref: this.state.match.route.ref}, props);
1619
// If we were passed an element, we need to clone it before passing it along.

lib/matchRoutes.js

+21-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var invariant = require('react/lib/invariant');
55
var React = require('react');
66
var cloneWithProps = require('react/lib/cloneWithProps');
77
var assign = Object.assign || require('object.assign');
8+
var qs = require('qs');
89

910
var patternCache = {};
1011

@@ -17,12 +18,19 @@ var patternCache = {};
1718
function matchRoutes(routes, path) {
1819
var createCompiler = require('../index').createURLPatternCompiler;
1920

20-
var match, page, notFound;
21+
var match, page, notFound, queryObj;
2122

2223
if (!Array.isArray(routes)) {
2324
routes = [routes];
2425
}
2526

27+
path = path.split('?');
28+
var pathToMatch = path[0];
29+
var queryString = path[1];
30+
if (queryString) {
31+
queryObj = qs.parse(queryString);
32+
}
33+
2634
for (var i = 0, len = routes.length; i < len; i++) {
2735
var current = routes[i];
2836
// Simply skip null or undefined to allow ternaries in route definitions
@@ -40,7 +48,7 @@ function matchRoutes(routes, path) {
4048
var pattern = patternCache[current.props.path] ||
4149
new URLPattern(current.props.path, createCompiler(current.props));
4250
if (!page) {
43-
match = pattern.match(path);
51+
match = pattern.match(pathToMatch);
4452
if (match) {
4553
page = current;
4654
}
@@ -53,6 +61,7 @@ function matchRoutes(routes, path) {
5361
if (match && match._ && !Array.isArray(match._)) {
5462
match._ = [match._];
5563
}
64+
5665
}
5766
}
5867
if (!notFound && current.props.path === null) {
@@ -61,9 +70,10 @@ function matchRoutes(routes, path) {
6170
}
6271

6372
return new Match(
64-
path,
73+
pathToMatch,
6574
page ? page : notFound ? notFound : null,
66-
match
75+
match,
76+
queryObj
6777
);
6878
}
6979

@@ -89,10 +99,11 @@ function parseMatch(current, match) {
8999
*
90100
* @private
91101
*/
92-
function Match(path, route, match) {
102+
function Match(path, route, match, query) {
93103
this.path = path;
94104
this.route = route;
95105
this.match = match;
106+
this.query = query;
96107

97108
this.unmatchedPath = this.match && this.match._ ?
98109
this.match._[0] :
@@ -107,9 +118,14 @@ Match.prototype.getHandler = function() {
107118
if (!this.route) return undefined;
108119

109120
var props = assign({}, this.route.props, this.match);
121+
// Querystring is assigned as _query.
122+
props._query = this.query || {};
123+
124+
// Delete props that shouldn't be passed to the handler.
110125
delete props.pattern;
111126
delete props.path;
112127
delete props.handler;
128+
113129
var handler = this.route.props.handler;
114130
// Passed an element - clone it with the props from the route
115131
if (React.isValidElement(handler)) {

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"dependencies": {
77
"envify": "^3.4.0",
88
"object.assign": "^3.0.0",
9+
"qs": "^4.0.0",
910
"url-pattern": "~0.9.0",
1011
"urllite": "~0.5.0"
1112
},

tests/browser.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ var a = React.createFactory('a');
2626
function divProps(children, prop) {
2727
return React.createClass({
2828
render: function() {
29-
return div(children, this.props[prop]);
29+
var propVal = this.props[prop];
30+
if (typeof propVal === 'object') propVal = JSON.stringify(propVal);
31+
return div(children, propVal);
3032
}
3133
});
3234
}
@@ -110,6 +112,10 @@ describe('Routing', function() {
110112
path: '/__zuul/transient',
111113
handler: div(null, 'i\'m transient')
112114
}),
115+
Location({
116+
path: '/__zuul/query',
117+
handler: divProps(null, '_query')
118+
}),
113119
Location({
114120
path: '/__zuul/:slug',
115121
handler: divProps(null, 'slug')
@@ -173,6 +179,15 @@ describe('Routing', function() {
173179
});
174180
});
175181

182+
it('navigates with a querystring and parses it', function(done) {
183+
assertRendered('mainpage');
184+
router.navigate('/__zuul/query?foo=bar&baz=biff&num=1');
185+
delay(function() {
186+
assertRendered(JSON.stringify({foo: 'bar', baz: 'biff', num: "1"}));
187+
done();
188+
});
189+
});
190+
176191
it('handles "popstate" event', function(done) {
177192
assertRendered('mainpage');
178193
router.navigate('/__zuul/hello', function() {

tests/matchRoutes.js

+11
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,17 @@ describe('matchRoutes', function() {
150150
assert.strictEqual(match.unmatchedPath, null);
151151
});
152152

153+
it('matches query strings', function() {
154+
var match = matchRoutes(routes, '/cat/hello?foo=bar&baz=biff');
155+
assert(match.route);
156+
assert.strictEqual(match.route.props.handler.props.name, 'cat');
157+
assert.deepEqual(match.match, {id: 'hello'});
158+
assert.strictEqual(match.path, '/cat/hello');
159+
assert.strictEqual(match.matchedPath, '/cat/hello');
160+
assert.strictEqual(match.unmatchedPath, null);
161+
assert.deepEqual(match.query, {foo : 'bar', baz: 'biff'});
162+
});
163+
153164
it('handles not found', function() {
154165
var match = matchRoutes(routes, '/hm');
155166
assert(match.route);

0 commit comments

Comments
 (0)