Skip to content

Commit

Permalink
fix: make sure errors$ is nexted when setErrors is called manually
Browse files Browse the repository at this point in the history
  • Loading branch information
Burgov committed Sep 15, 2020
1 parent a5bae1d commit ce820fc
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 5 deletions.
6 changes: 5 additions & 1 deletion projects/ngneat/reactive-forms/src/lib/control-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,13 @@ export function controlStatusChanges$<T>(control: AbstractControl<T>): Observabl
);
}

export function controlErrorChanges$<E>(control: AbstractControl): Observable<E | null> {
export function controlErrorChanges$<E>(
control: AbstractControl,
errors$: Observable<Partial<E>>
): Observable<E | null> {
return merge(
defer(() => of(control.errors as E)),
errors$ as Observable<E>,
control.valueChanges.pipe(
map(() => control.errors as E),
distinctUntilChanged((a, b) => compareErrors(a, b))
Expand Down
4 changes: 4 additions & 0 deletions projects/ngneat/reactive-forms/src/lib/formArray.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,13 @@ describe('FormArray', () => {
control.setValidators(validator);
control.errors$.subscribe(spy);
expect(spy).toHaveBeenCalledWith({ minimum: 4 });
spy.mockReset();
control.push(new FormControl('Name'));
control.push(new FormControl('Phone'));
expect(spy).toHaveBeenCalledWith(null);
spy.mockReset();
control.setErrors({ myError: 'So wrong' });
expect(spy).toHaveBeenCalledWith({ myError: 'So wrong' });
});

it('should remove', () => {
Expand Down
4 changes: 3 additions & 1 deletion projects/ngneat/reactive-forms/src/lib/formArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export class FormArray<T = any, E extends object = any> extends NgFormArray {

private touchChanges = new Subject<boolean>();
private dirtyChanges = new Subject<boolean>();
private errorsSubject = new Subject<Partial<E>>();

readonly touch$ = this.touchChanges.asObservable().pipe(distinctUntilChanged());
readonly dirty$ = this.dirtyChanges.asObservable().pipe(distinctUntilChanged());
Expand All @@ -50,7 +51,7 @@ export class FormArray<T = any, E extends object = any> extends NgFormArray {
readonly disabled$ = controlDisabled$(this);
readonly enabled$ = controlEnabled$(this);
readonly status$ = controlStatusChanges$(this);
readonly errors$ = controlErrorChanges$<E>(this);
readonly errors$ = controlErrorChanges$<E>(this, this.errorsSubject.asObservable());

get asyncValidator(): AsyncValidatorFn<T[]> | null {
return super.asyncValidator;
Expand Down Expand Up @@ -184,6 +185,7 @@ export class FormArray<T = any, E extends object = any> extends NgFormArray {
}

setErrors(errors: Partial<E> | null, opts: EmitEvent = {}) {
this.errorsSubject.next(errors);
return super.setErrors(errors, opts);
}

Expand Down
8 changes: 7 additions & 1 deletion projects/ngneat/reactive-forms/src/lib/formControl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,16 @@ describe('FormControl', () => {
const spy = jest.fn();
control.errors$.subscribe(spy);
expect(spy).toHaveBeenCalledWith({ required: true });
spy.mockReset();
control.patchValue(null);
control.patchValue('');
expect(spy).toHaveBeenCalledTimes(2);
expect(spy).toHaveBeenCalledTimes(1);
spy.mockReset();
control.patchValue('Test');
expect(spy).toHaveBeenCalledWith(null);
spy.mockReset();

control.setErrors({ myError: 'So wrong' });
expect(spy).toHaveBeenCalledWith({ myError: 'So wrong' });
});
});
4 changes: 3 additions & 1 deletion projects/ngneat/reactive-forms/src/lib/formControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export class FormControl<T = any, E extends object = any> extends NgFormControl

private touchChanges = new Subject<boolean>();
private dirtyChanges = new Subject<boolean>();
private errorsSubject = new Subject<Partial<E>>();

readonly touch$ = this.touchChanges.asObservable().pipe(distinctUntilChanged());
readonly dirty$ = this.dirtyChanges.asObservable().pipe(distinctUntilChanged());
Expand All @@ -49,7 +50,7 @@ export class FormControl<T = any, E extends object = any> extends NgFormControl
readonly disabled$ = controlDisabled$<T>(this);
readonly enabled$ = controlEnabled$<T>(this);
readonly status$ = controlStatusChanges$<T>(this);
readonly errors$ = controlErrorChanges$<E>(this);
readonly errors$ = controlErrorChanges$<E>(this, this.errorsSubject.asObservable());

get asyncValidator(): AsyncValidatorFn<T> | null {
return super.asyncValidator;
Expand Down Expand Up @@ -157,6 +158,7 @@ export class FormControl<T = any, E extends object = any> extends NgFormControl
}

setErrors(errors: Partial<E> | null, opts: EmitEvent = {}) {
this.errorsSubject.next(errors);
return super.setErrors(errors, opts);
}

Expand Down
4 changes: 4 additions & 0 deletions projects/ngneat/reactive-forms/src/lib/formGroup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,12 @@ describe('FormGroup', () => {
const spy = jest.fn();
control.errors$.subscribe(spy);
expect(spy).toHaveBeenCalledWith(null);
spy.mockReset();
control.patchValue({ name: 'Test' });
expect(spy).toHaveBeenCalledWith({ invalidName: true });
spy.mockReset();
control.setErrors({ myError: 'So wrong' });
expect(spy).toHaveBeenCalledWith({ myError: 'So wrong' });
});

describe('.persist()', () => {
Expand Down
4 changes: 3 additions & 1 deletion projects/ngneat/reactive-forms/src/lib/formGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export class FormGroup<T extends Obj = any, E extends object = any> extends NgFo

private touchChanges = new Subject<boolean>();
private dirtyChanges = new Subject<boolean>();
private errorsSubject = new Subject<Partial<E>>();

touch$ = this.touchChanges.asObservable().pipe(distinctUntilChanged());
dirty$ = this.dirtyChanges.asObservable().pipe(distinctUntilChanged());
Expand All @@ -60,7 +61,7 @@ export class FormGroup<T extends Obj = any, E extends object = any> extends NgFo
readonly disabled$ = controlDisabled$<T>(this);
readonly enabled$ = controlEnabled$<T>(this);
readonly status$ = controlStatusChanges$<T>(this);
readonly errors$ = controlErrorChanges$<E>(this);
readonly errors$ = controlErrorChanges$<E>(this, this.errorsSubject.asObservable());

get asyncValidator(): AsyncValidatorFn<T> | null {
return super.asyncValidator;
Expand Down Expand Up @@ -226,6 +227,7 @@ export class FormGroup<T extends Obj = any, E extends object = any> extends NgFo
}

setErrors(errors: Partial<E> | null, opts: EmitEvent = {}) {
this.errorsSubject.next(errors);
return super.setErrors(errors, opts);
}

Expand Down

0 comments on commit ce820fc

Please sign in to comment.