Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 30 additions & 7 deletions modules/@angular/router/src/url_tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,9 +370,14 @@ function serializeParams(params: {[key: string]: string}): string {
return pairs(params).map(p => `;${encode(p.first)}=${encode(p.second)}`).join('');
}

function serializeQueryParams(params: {[key: string]: string}): string {
const strs = pairs(params).map(p => `${encode(p.first)}=${encode(p.second)}`);
return strs.length > 0 ? `?${strs.join("&")}` : '';
function serializeQueryParams(params: {[key: string]: any}): string {
const strParams: string[] = Object.keys(params).map((name) => {
const value = params[name];
return Array.isArray(value) ? value.map(v => `${encode(name)}=${encode(v)}`).join('&') :
`${encode(name)}=${encode(value)}`;
});

return strParams.length ? `?${strParams.join("&")}` : '';
}

class Pair<A, B> {
Expand All @@ -388,21 +393,23 @@ function pairs<T>(obj: {[key: string]: T}): Pair<string, T>[] {
return res;
}

const SEGMENT_RE = /^[^\/\(\)\?;=&#]+/;
const SEGMENT_RE = /^[^\/()?;=&#]+/;
function matchSegments(str: string): string {
SEGMENT_RE.lastIndex = 0;
const match = str.match(SEGMENT_RE);
return match ? match[0] : '';
}

const QUERY_PARAM_RE = /^[^=\?&#]+/;
const QUERY_PARAM_RE = /^[^=?&#]+/;
// Return the name of the query param at the start of the string or an empty string
function matchQueryParams(str: string): string {
QUERY_PARAM_RE.lastIndex = 0;
const match = str.match(SEGMENT_RE);
return match ? match[0] : '';
}

const QUERY_PARAM_VALUE_RE = /^[^\?&#]+/;
const QUERY_PARAM_VALUE_RE = /^[^?&#]+/;
// Return the value of the query param at the start of the string or an empty string
function matchUrlQueryParamValue(str: string): string {
QUERY_PARAM_VALUE_RE.lastIndex = 0;
const match = str.match(QUERY_PARAM_VALUE_RE);
Expand Down Expand Up @@ -534,6 +541,7 @@ class UrlParser {
params[decode(key)] = decode(value);
}

// Parse a single query parameter `name[=value]`
parseQueryParam(params: {[key: string]: any}): void {
const key = matchQueryParams(this.remaining);
if (!key) {
Expand All @@ -549,7 +557,22 @@ class UrlParser {
this.capture(value);
}
}
params[decode(key)] = decode(value);

const decodedKey = decode(key);
const decodedVal = decode(value);

if (params.hasOwnProperty(decodedKey)) {
// Append to existing values
let currentVal = params[decodedKey];
if (!Array.isArray(currentVal)) {
currentVal = [currentVal];
params[decodedKey] = currentVal;
}
currentVal.push(decodedVal);
} else {
// Create a new value
params[decodedKey] = decodedVal;
}
}

parseParens(allowPrimary: boolean): {[key: string]: UrlSegmentGroup} {
Expand Down
5 changes: 5 additions & 0 deletions modules/@angular/router/test/url_serializer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ describe('url serializer', () => {
expect(url.serialize(tree)).toEqual('/one?a=');
});

it('should handle multiple query params of the same name into an array', () => {
const tree = url.parse('/one?a=foo&a=bar&a=swaz');
expect(tree.queryParams).toEqual({a: ['foo', 'bar', 'swaz']});
});

it('should parse fragment', () => {
const tree = url.parse('/one#two');
expect(tree.fragment).toEqual('two');
Expand Down