The url_tree equalQueryParams and containsQueryParam methods did not handle query params that has arrays, which resulted in the routerLinkActive to not behave as expected, change was made to ensure query params with arrays are handled correctly fixes #22223 PR Close #22666
153 lines
4.0 KiB
TypeScript
153 lines
4.0 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import {Route, UrlMatchResult} from './config';
|
|
import {UrlSegment, UrlSegmentGroup} from './url_tree';
|
|
|
|
|
|
/**
|
|
* The primary routing outlet.
|
|
*
|
|
* @publicApi
|
|
*/
|
|
export const PRIMARY_OUTLET = 'primary';
|
|
|
|
/**
|
|
* A collection of matrix and query URL parameters.
|
|
* @see `convertToParamMap()`
|
|
* @see `ParamMap`
|
|
*
|
|
* @publicApi
|
|
*/
|
|
export type Params = {
|
|
[key: string]: any;
|
|
};
|
|
|
|
/**
|
|
* A map that provides access to the required and optional parameters
|
|
* specific to a route.
|
|
* The map supports retrieving a single value with `get()`
|
|
* or multiple values with `getAll()`.
|
|
*
|
|
* @see [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
|
|
*
|
|
* @publicApi
|
|
*/
|
|
export interface ParamMap {
|
|
/**
|
|
* Reports whether the map contains a given parameter.
|
|
* @param name The parameter name.
|
|
* @returns True if the map contains the given parameter, false otherwise.
|
|
*/
|
|
has(name: string): boolean;
|
|
/**
|
|
* Retrieves a single value for a parameter.
|
|
* @param name The parameter name.
|
|
* @return The parameter's single value,
|
|
* or the first value if the parameter has multiple values,
|
|
* or `null` when there is no such parameter.
|
|
*/
|
|
get(name: string): string|null;
|
|
/**
|
|
* Retrieves multiple values for a parameter.
|
|
* @param name The parameter name.
|
|
* @return An array containing one or more values,
|
|
* or an empty array if there is no such parameter.
|
|
*
|
|
*/
|
|
getAll(name: string): string[];
|
|
|
|
/** Names of the parameters in the map. */
|
|
readonly keys: string[];
|
|
}
|
|
|
|
class ParamsAsMap implements ParamMap {
|
|
private params: Params;
|
|
|
|
constructor(params: Params) { this.params = params || {}; }
|
|
|
|
has(name: string): boolean { return this.params.hasOwnProperty(name); }
|
|
|
|
get(name: string): string|null {
|
|
if (this.has(name)) {
|
|
const v = this.params[name];
|
|
return Array.isArray(v) ? v[0] : v;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
getAll(name: string): string[] {
|
|
if (this.has(name)) {
|
|
const v = this.params[name];
|
|
return Array.isArray(v) ? v : [v];
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
get keys(): string[] { return Object.keys(this.params); }
|
|
}
|
|
|
|
/**
|
|
* Converts a `Params` instance to a `ParamMap`.
|
|
* @param params The instance to convert.
|
|
* @returns The new map instance.
|
|
*
|
|
* @publicApi
|
|
*/
|
|
export function convertToParamMap(params: Params): ParamMap {
|
|
return new ParamsAsMap(params);
|
|
}
|
|
|
|
const NAVIGATION_CANCELING_ERROR = 'ngNavigationCancelingError';
|
|
|
|
export function navigationCancelingError(message: string) {
|
|
const error = Error('NavigationCancelingError: ' + message);
|
|
(error as any)[NAVIGATION_CANCELING_ERROR] = true;
|
|
return error;
|
|
}
|
|
|
|
export function isNavigationCancelingError(error: Error) {
|
|
return error && (error as any)[NAVIGATION_CANCELING_ERROR];
|
|
}
|
|
|
|
// Matches the route configuration (`route`) against the actual URL (`segments`).
|
|
export function defaultUrlMatcher(
|
|
segments: UrlSegment[], segmentGroup: UrlSegmentGroup, route: Route): UrlMatchResult|null {
|
|
const parts = route.path !.split('/');
|
|
|
|
if (parts.length > segments.length) {
|
|
// The actual URL is shorter than the config, no match
|
|
return null;
|
|
}
|
|
|
|
if (route.pathMatch === 'full' &&
|
|
(segmentGroup.hasChildren() || parts.length < segments.length)) {
|
|
// The config is longer than the actual URL but we are looking for a full match, return null
|
|
return null;
|
|
}
|
|
|
|
const posParams: {[key: string]: UrlSegment} = {};
|
|
|
|
// Check each config part against the actual URL
|
|
for (let index = 0; index < parts.length; index++) {
|
|
const part = parts[index];
|
|
const segment = segments[index];
|
|
const isParameter = part.startsWith(':');
|
|
if (isParameter) {
|
|
posParams[part.substring(1)] = segment;
|
|
} else if (part !== segment.path) {
|
|
// The actual URL part does not match the config, no match
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return {consumed: segments.slice(0, parts.length), posParams};
|
|
}
|