From a9d40a12d80589577e1eaf2a85fec4961f380e1e Mon Sep 17 00:00:00 2001 From: Rafael Santana Date: Sun, 7 Mar 2021 18:51:17 -0300 Subject: [PATCH] feat: add ignoreInvalidForm config --- .../src/lib/BindQueryParamsManager.ts | 17 +++++- .../src/lib/QueryParamDef.ts | 4 ++ .../bind-query-params/src/lib/lib.spec.ts | 60 ++++++++++++++++++- .../bind-query-params/src/lib/options.ts | 4 +- .../ngneat/bind-query-params/src/lib/types.ts | 2 + 5 files changed, 83 insertions(+), 4 deletions(-) diff --git a/projects/ngneat/bind-query-params/src/lib/BindQueryParamsManager.ts b/projects/ngneat/bind-query-params/src/lib/BindQueryParamsManager.ts index 4646515..f161a64 100644 --- a/projects/ngneat/bind-query-params/src/lib/BindQueryParamsManager.ts +++ b/projects/ngneat/bind-query-params/src/lib/BindQueryParamsManager.ts @@ -2,7 +2,7 @@ import { FormGroup } from '@angular/forms'; import { merge, Subject } from 'rxjs'; import { Router } from '@angular/router'; import { coerceArray, resolveParams } from './utils'; -import { auditTime, map, takeUntil } from 'rxjs/operators'; +import { auditTime, debounceTime, filter, map, takeUntil } from 'rxjs/operators'; import { BindQueryParamsOptions, QueryParamParams, ResolveParamsOption } from './types'; import { QueryParamDef } from './QueryParamDef'; import set from 'lodash.set'; @@ -31,7 +31,20 @@ export class BindQueryParamsManager { this.updateControl(this.defs, { emitEvent: true }, (def) => def.strategy === 'twoWay'); const controls = this.defs.map((def) => { - return this.group.get(def.path)!.valueChanges.pipe( + const control = this.group.get(def.path)!; + return control.valueChanges.pipe( + debounceTime(0), + filter(() => { + if (this.options.ignoreInvalidForm) { + return this.group.valid; + } + + if (def.ignoreInvalidForm) { + return control.valid; + } + + return true; + }), map((value) => ({ def, value, diff --git a/projects/ngneat/bind-query-params/src/lib/QueryParamDef.ts b/projects/ngneat/bind-query-params/src/lib/QueryParamDef.ts index c46375b..4e62e24 100644 --- a/projects/ngneat/bind-query-params/src/lib/QueryParamDef.ts +++ b/projects/ngneat/bind-query-params/src/lib/QueryParamDef.ts @@ -4,6 +4,10 @@ import { parse } from './utils'; export class QueryParamDef { constructor(private config: QueryParamParams) {} + get ignoreInvalidForm() { + return this.config.ignoreInvalidForm; + } + get queryKey() { return this.config.queryKey; } diff --git a/projects/ngneat/bind-query-params/src/lib/lib.spec.ts b/projects/ngneat/bind-query-params/src/lib/lib.spec.ts index 15516b6..08acbf2 100644 --- a/projects/ngneat/bind-query-params/src/lib/lib.spec.ts +++ b/projects/ngneat/bind-query-params/src/lib/lib.spec.ts @@ -1,5 +1,5 @@ import { BIND_QUERY_PARAMS_OPTIONS, BindQueryParamsFactory } from '@ngneat/bind-query-params'; -import { FormControl, FormGroup } from '@angular/forms'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; import { createComponentFactory, Spectator } from '@ngneat/spectator'; import { Component } from '@angular/core'; import { Router } from '@angular/router'; @@ -29,6 +29,7 @@ function assertRouterCall(spectator: Spectator, queryParams: Reco } interface Params { + withMinlengthValidator: string; searchTerm: string; 'withBrackets[gte]': string; showErrors: boolean; @@ -46,6 +47,7 @@ interface Params { }) class HomeComponent { group = new FormGroup({ + withMinlengthValidator: new FormControl('', [Validators.minLength(5)]), searchTerm: new FormControl(), 'withBrackets[gte]': new FormControl(), showErrors: new FormControl(false), @@ -64,6 +66,7 @@ class HomeComponent { bindQueryParams = this.factory .create([ + { queryKey: 'withMinlengthValidator', ignoreInvalidForm: true }, { queryKey: 'searchTerm' }, { queryKey: 'withBrackets[gte]' }, { queryKey: 'showErrors', type: 'boolean' }, @@ -121,6 +124,61 @@ describe('BindQueryParams', () => { })); }); + describe('ignoreInvalidForm', () => { + it('should navigate only when control is valid', fakeAsync(() => { + spectator = createComponent(); + const router = spectator.inject(Router); + + spectator.component.group.patchValue({ + withMinlengthValidator: 'with', + }); + + tick(); + + expect(router.navigate).not.toHaveBeenCalled(); + + spectator.component.group.patchValue({ + withMinlengthValidator: 'with1', + }); + + tick(); + + assertRouterCall(spectator, { withMinlengthValidator: 'with1' }); + })); + + it('should navigate only when group is valid', fakeAsync(() => { + spectator = createComponent({ + providers: [ + { + provide: BIND_QUERY_PARAMS_OPTIONS, + useValue: { + ignoreInvalidForm: true, + windowRef: window, + }, + }, + ], + }); + const router = spectator.inject(Router); + + spectator.component.group.patchValue({ + searchTerm: 'term', + withMinlengthValidator: 'with', + }); + + tick(); + + expect(router.navigate).not.toHaveBeenCalled(); + + spectator.component.group.patchValue({ + withMinlengthValidator: 'with1', + }); + + tick(); + + assertRouterCall(spectator, { withMinlengthValidator: 'with1' }); + })); + }); + describe('string', () => { it('control => query', fakeAsync(() => { spectator = createComponent(); diff --git a/projects/ngneat/bind-query-params/src/lib/options.ts b/projects/ngneat/bind-query-params/src/lib/options.ts index 5d63af8..f79eac6 100644 --- a/projects/ngneat/bind-query-params/src/lib/options.ts +++ b/projects/ngneat/bind-query-params/src/lib/options.ts @@ -1,9 +1,11 @@ import { InjectionToken } from '@angular/core'; +import { BindQueryParamsOptions } from './types'; -export const BIND_QUERY_PARAMS_OPTIONS = new InjectionToken('BIND_QUERY_PARAMS_OPTIONS', { +export const BIND_QUERY_PARAMS_OPTIONS = new InjectionToken('BIND_QUERY_PARAMS_OPTIONS', { providedIn: 'root', factory() { return { + ignoreInvalidForm: false, windowRef: window, }; }, diff --git a/projects/ngneat/bind-query-params/src/lib/types.ts b/projects/ngneat/bind-query-params/src/lib/types.ts index b068fd5..aec4782 100644 --- a/projects/ngneat/bind-query-params/src/lib/types.ts +++ b/projects/ngneat/bind-query-params/src/lib/types.ts @@ -3,6 +3,7 @@ import { QueryParamDef } from './QueryParamDef'; export type ParamDefType = 'boolean' | 'array' | 'number' | 'string' | 'object'; export type QueryParamParams = { + ignoreInvalidForm?: boolean; queryKey: keyof QueryParams & string; path?: string; type?: ParamDefType; @@ -12,6 +13,7 @@ export type QueryParamParams = { }; export interface BindQueryParamsOptions { + ignoreInvalidForm?: boolean; windowRef: Window; }