diff --git a/packages/router/src/url_tree.ts b/packages/router/src/url_tree.ts index 7dd79e97c9..c1cee55f97 100644 --- a/packages/router/src/url_tree.ts +++ b/packages/router/src/url_tree.ts @@ -39,7 +39,6 @@ function equalSegmentGroups(container: UrlSegmentGroup, containee: UrlSegmentGro } function containsQueryParams(container: Params, containee: Params): boolean { - // TODO: This does not handle array params correctly. return Object.keys(containee).length <= Object.keys(container).length && Object.keys(containee).every(key => equalArraysOrString(container[key], containee[key])); } diff --git a/packages/router/src/utils/collection.ts b/packages/router/src/utils/collection.ts index 637cb7a9f3..f3a9359a6a 100644 --- a/packages/router/src/utils/collection.ts +++ b/packages/router/src/utils/collection.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {NgModuleFactory, ɵisObservable as isObservable, ɵisPromise as isPromise} from '@angular/core'; +import {ɵisObservable as isObservable, ɵisPromise as isPromise} from '@angular/core'; import {from, Observable, of} from 'rxjs'; import {concatAll, last as lastValue, map} from 'rxjs/operators'; @@ -45,8 +45,10 @@ export function shallowEqual(a: Params, b: Params): boolean { */ export function equalArraysOrString(a: string|string[], b: string|string[]) { if (Array.isArray(a) && Array.isArray(b)) { - if (a.length != b.length) return false; - return a.every(aItem => b.indexOf(aItem) > -1); + if (a.length !== b.length) return false; + const aSorted = [...a].sort(); + const bSorted = [...b].sort(); + return aSorted.every((val, index) => bSorted[index] === val); } else { return a === b; } diff --git a/packages/router/test/url_tree.spec.ts b/packages/router/test/url_tree.spec.ts index f2126f89b9..34aac7b3b2 100644 --- a/packages/router/test/url_tree.spec.ts +++ b/packages/router/test/url_tree.spec.ts @@ -67,6 +67,24 @@ describe('UrlTree', () => { expect(containsTree(t1, t2, true)).toBe(false); }); + it('should return false when queryParams are not the same', () => { + const t1 = serializer.parse('/one/two?test=4&test=4&test=2'); + const t2 = serializer.parse('/one/two?test=4&test=3&test=2'); + expect(containsTree(t1, t2, false)).toBe(false); + }); + + it('should return true when queryParams are the same in different order', () => { + const t1 = serializer.parse('/one/two?test=4&test=3&test=2'); + const t2 = serializer.parse('/one/two?test=2&test=3&test=4'); + expect(containsTree(t1, t2, false)).toBe(true); + }); + + it('should return true when queryParams are the same in different order', () => { + const t1 = serializer.parse('/one/two?test=4&test=4&test=1'); + const t2 = serializer.parse('/one/two?test=1&test=4&test=4'); + expect(containsTree(t1, t2, false)).toBe(true); + }); + it('should return false when containee is missing queryParams', () => { const t1 = serializer.parse('/one/two?page=5'); const t2 = serializer.parse('/one/two');