Skip to content

Commit 0234ebf

Browse files
committed
feat(core): Added emptyOn and compareWith options
This allows defining a non-null "default value" for which the query parameter should be removed. We now also use compareWith to determine whether to ignore a route update or not.
1 parent 15ce1ee commit 0234ebf

7 files changed

Lines changed: 67 additions & 16 deletions

File tree

projects/ngqp-demo/src/app/playground/playground.component.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@ export class PlaygroundComponent {
1212
this.paramGroup = queryParamBuilder.group({
1313
searchText: queryParamBuilder.param({
1414
name: 'q',
15-
debounceTime: 1000,
15+
debounceTime: 250,
16+
emptyOn: 'foo'
1617
}),
1718
checker: queryParamBuilder.booleanParam({
1819
name: 'yesOrNo',
20+
emptyOn: true,
1921
}),
2022
counter: queryParamBuilder.numericParam({
2123
name: 'ctr',
24+
emptyOn: 5,
2225
}),
2326
range: queryParamBuilder.numericParam({
2427
name: 'range',
28+
emptyOn: 5,
2529
}),
2630
});
2731
}

projects/ngqp/core/src/lib/core.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export { QueryParamBuilder } from './query-param-builder.service';
55
export { QueryParamModule } from './query-param.module';
66

77
export {
8+
createEmptyOnSerializer,
89
createStringSerializer,
910
createStringDeserializer,
1011
createNumberSerializer,

projects/ngqp/core/src/lib/model.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { isOptionalFunction, wrapTryCatch } from './util';
1+
import { Comparator, isOptionalFunction, wrapTryCatch } from './util';
2+
import { createEmptyOnDeserializer, createEmptyOnSerializer } from './serializers';
23

34
/** TODO Documentation */
45
export type ParamSerializer<T> = (model: T | null) => string | null;
@@ -10,10 +11,18 @@ export type ParamDeserializer<T> = (value: string | null) => T | null;
1011
* TODO Documentation
1112
*/
1213
export interface QueryParamControlOpts<T> {
14+
/** TODO Documentation */
1315
name: string;
16+
/** TODO Documentation */
1417
serialize: ParamSerializer<T>;
18+
/** TODO Documentation */
1519
deserialize: ParamDeserializer<T>;
20+
/** TODO Documentation */
21+
compareWith: Comparator<T>;
22+
/** TODO Documentation */
1623
debounceTime?: number | null;
24+
/** TODO Documentation */
25+
emptyOn?: T | null;
1726
}
1827

1928
/**
@@ -35,23 +44,26 @@ export class QueryParamGroup {
3544
*/
3645
export class QueryParamControl<T> {
3746

38-
/** TODO Documentation */
39-
public name: string | null = null;
47+
/** TODO Documentation See QueryParamControlOpts */
48+
public name: string | null;
4049

41-
/** TODO Documentation */
50+
/** TODO Documentation See QueryParamControlOpts */
4251
public serialize: ParamSerializer<T>;
4352

44-
/** TODO Documentation */
53+
/** TODO Documentation See QueryParamControlOpts */
4554
public deserialize: ParamDeserializer<T>;
4655

47-
/** TODO Documentation */
48-
public debounceTime: number | null = null;
56+
/** TODO Documentation See QueryParamControlOpts */
57+
public compareWith: Comparator<T>;
58+
59+
/** TODO Documentation See QueryParamControlOpts */
60+
public debounceTime: number | null;
4961

5062
/** TODO Documentation */
5163
public value: T = null;
5264

5365
constructor(opts: QueryParamControlOpts<T>) {
54-
const { name, serialize, deserialize, debounceTime } = opts;
66+
const { name, serialize, deserialize, debounceTime, emptyOn, compareWith } = opts;
5567

5668
if (!isOptionalFunction(serialize)) {
5769
throw new Error(`serialize must be a function, but received ${serialize}`);
@@ -61,9 +73,20 @@ export class QueryParamControl<T> {
6173
throw new Error(`deserialize must be a function, but received ${deserialize}`);
6274
}
6375

76+
if (!isOptionalFunction(compareWith)) {
77+
throw new Error(`compareWith must be a function, but received ${compareWith}`);
78+
}
79+
6480
this.name = name;
65-
this.serialize = wrapTryCatch(serialize, `Error while serializing value for ${name || 'control'}`);
66-
this.deserialize = wrapTryCatch(deserialize, `Error while deserializing value for ${name || 'control'}`);
81+
this.serialize = wrapTryCatch(
82+
createEmptyOnSerializer(serialize, emptyOn, compareWith),
83+
`Error while serializing value for ${name || 'control'}`
84+
);
85+
this.deserialize = wrapTryCatch(
86+
createEmptyOnDeserializer(deserialize, emptyOn),
87+
`Error while deserializing value for ${name || 'control'}`
88+
);
89+
this.compareWith = compareWith;
6790
this.debounceTime = debounceTime;
6891
}
6992

projects/ngqp/core/src/lib/query-param-builder.service.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import {
88
DEFAULT_STRING_DESERIALIZER,
99
DEFAULT_STRING_SERIALIZER
1010
} from './serializers';
11+
import { LOOSE_IDENTITY_COMPARATOR } from './util';
1112

1213
type OverwritePartial<T1, T2 extends keyof T1> = Pick<T1, Exclude<keyof T1, T2>> & Partial<Pick<T1, T2>>;
13-
export type QueryParamControlOptsInput<T> = OverwritePartial<QueryParamControlOpts<T>, 'serialize' | 'deserialize'>;
14+
export type QueryParamControlOptsInput<T> = OverwritePartial<QueryParamControlOpts<T>, 'serialize' | 'deserialize' | 'compareWith'>;
1415

1516
/**
1617
* TODO Documentation
@@ -48,6 +49,7 @@ export class QueryParamBuilder {
4849
return new QueryParamControl({
4950
serialize: DEFAULT_STRING_SERIALIZER,
5051
deserialize: DEFAULT_STRING_DESERIALIZER,
52+
compareWith: LOOSE_IDENTITY_COMPARATOR,
5153
...opts,
5254
});
5355
}
@@ -59,6 +61,7 @@ export class QueryParamBuilder {
5961
return new QueryParamControl({
6062
serialize: DEFAULT_NUMBER_SERIALIZER,
6163
deserialize: DEFAULT_NUMBER_DESERIALIZER,
64+
compareWith: LOOSE_IDENTITY_COMPARATOR,
6265
...opts,
6366
});
6467
}
@@ -70,6 +73,7 @@ export class QueryParamBuilder {
7073
return new QueryParamControl({
7174
serialize: DEFAULT_BOOLEAN_SERIALIZER,
7275
deserialize: DEFAULT_BOOLEAN_DESERIALIZER,
76+
compareWith: LOOSE_IDENTITY_COMPARATOR,
7377
...opts,
7478
});
7579
}
@@ -88,8 +92,6 @@ export class QueryParamBuilder {
8892

8993
return this.param({
9094
name: controlName,
91-
serialize: DEFAULT_STRING_SERIALIZER,
92-
deserialize: DEFAULT_STRING_DESERIALIZER,
9395
});
9496
}
9597

projects/ngqp/core/src/lib/query-param-group.directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export class QueryParamGroupDirective implements OnDestroy {
6969
distinctUntilChanged(),
7070
map(param => control.deserialize(param)),
7171
).subscribe(newModel => {
72-
if (control.serialize(newModel) === control.serialize(control.value)) {
72+
if (control.compareWith(newModel, control.value)) {
7373
return;
7474
}
7575

projects/ngqp/core/src/lib/serializers.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
import { ParamDeserializer, ParamSerializer } from './model';
2-
import { isMissing } from './util';
2+
import { Comparator, isMissing } from './util';
3+
4+
/**
5+
* TODO Documentation
6+
*/
7+
export function createEmptyOnSerializer<T>(serializer: ParamSerializer<T>, emptyOn: T, compareWith: Comparator<T>): ParamSerializer<T> {
8+
return (model: T | null) => compareWith(model, emptyOn) ? null : serializer(model);
9+
}
10+
11+
/**
12+
* TODO Documentation
13+
*/
14+
export function createEmptyOnDeserializer<T>(deserializer: ParamDeserializer<T>, emptyOn: T): ParamDeserializer<T> {
15+
return (value: string | null) => isMissing(value) ? emptyOn : deserializer(value);
16+
}
317

418
/**
519
* TODO Documentation

projects/ngqp/core/src/lib/util.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
/** TODO Documentation */
2+
export type Comparator<T> = (a: T, b: T) => boolean;
3+
4+
/** TODO Documentation */
5+
// tslint:disable-next-line:triple-equals
6+
export const LOOSE_IDENTITY_COMPARATOR = <T>(a: T, b: T) => a == b;
7+
18
/**
29
* TODO Documentation
310
*/

0 commit comments

Comments
 (0)