Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove on form update hook #129

Merged
merged 2 commits into from
Feb 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,6 @@ export class CrewMemberComponent extends NgxSubFormComponent<CrewMember> {

**Hooks**

- `onFormUpdate`: Allows you to react whenever the form is being modified. Instead of subscribing to `this.formGroup.valueChanges` or `this.formControls.someProp.valueChanges` you will not have to deal with anything asynchronous nor have to worry about subscriptions and memory leaks. Just implement the method `onFormUpdate(formUpdate: FormUpdate<FormInterface>): void` and if you need to know which property changed do a check like the following: `if (formUpdate.yourProperty) {}`. Be aware that this method will be called only when there are either local changes to the form or changes coming from subforms. If the parent `setValue` or `patchValue` this method won't be triggered
- `getFormGroupControlOptions`: Allows you to define control options for construction of the internal FormGroup. Use this to define form-level validators
- `createFormArrayControl`: Allows you to create the `FormControl` of a given property of your form (to define validators for example). When you want to use this hook, implement the following interface `NgxFormWithArrayControls`
- `handleEmissionRate`: Allows you to define a custom emission rate (top level or any sub level)
Expand Down
57 changes: 0 additions & 57 deletions projects/ngx-sub-form/src/lib/ngx-sub-form.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,63 +388,6 @@ describe(`NgxSubFormComponent`, () => {
});
});

describe(`onFormUpdate`, () => {
it(`should not call onFormUpdate when patched by the parent (through "writeValue")`, (done: () => void) => {
const spyOnFormUpdate = jasmine.createSpy();
subComponent.onFormUpdate = spyOnFormUpdate;
subComponent.registerOnChange(() => {});

setTimeout(() => {
spyOnFormUpdate.calls.reset();

subComponent.writeValue({ ...subComponent.formGroupValues, color: 'red' });

setTimeout(() => {
expect(spyOnFormUpdate).not.toHaveBeenCalled();

done();
}, 0);
}, 0);
});

it(`should call onFormUpdate everytime the form changes (local changes)`, (done: () => void) => {
const spyOnFormUpdate = jasmine.createSpy();
subComponent.onFormUpdate = spyOnFormUpdate;
subComponent.registerOnChange(() => {});

subComponent.formGroupControls.color.setValue(`red`);

setTimeout(() => {
expect(spyOnFormUpdate).toHaveBeenCalledWith({
color: true,
});

done();
}, 0);
});

it(`should correctly emit the onChange value only once when form is patched locally`, (done: () => void) => {
const spyOnFormUpdate = jasmine.createSpy();
const spyOnChange = jasmine.createSpy();
subComponent.onFormUpdate = spyOnFormUpdate;
subComponent.registerOnChange(spyOnChange);
(subComponent as any).emitInitialValueOnInit = false;

subComponent.formGroup.patchValue({ color: 'red', canFire: false });

setTimeout(() => {
expect(spyOnFormUpdate).toHaveBeenCalledWith({
canFire: true,
});

expect(spyOnChange).toHaveBeenCalledTimes(1);
expect(spyOnChange).toHaveBeenCalledWith({ color: 'red', canFire: false, crewMemberCount: 10 });

done();
}, 0);
});
});

describe('getFormGroupControlOptions', () => {
interface Numbered {
numberOne: number;
Expand Down
25 changes: 3 additions & 22 deletions projects/ngx-sub-form/src/lib/ngx-sub-form.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
ControlsType,
ArrayPropertyKey,
} from './ngx-sub-form-utils';
import { FormGroupOptions, NgxFormWithArrayControls, OnFormUpdate, TypedFormGroup } from './ngx-sub-form.types';
import { FormGroupOptions, NgxFormWithArrayControls, TypedFormGroup } from './ngx-sub-form.types';

type MapControlFunction<FormInterface, MapValue> = (ctrl: AbstractControl, key: keyof FormInterface) => MapValue;
type FilterControlFunction<FormInterface> = (
Expand All @@ -32,7 +32,7 @@ type FilterControlFunction<FormInterface> = (
) => boolean;

export abstract class NgxSubFormComponent<ControlInterface, FormInterface = ControlInterface>
implements ControlValueAccessor, Validator, OnDestroy, OnFormUpdate<FormInterface> {
implements ControlValueAccessor, Validator, OnDestroy {
public get formGroupControls(): ControlsType<FormInterface> {
// @note form-group-undefined we need the return null here because we do not want to expose the fact that
// the form can be undefined, it's handled internally to contain an Angular bug
Expand Down Expand Up @@ -170,8 +170,6 @@ export abstract class NgxSubFormComponent<ControlInterface, FormInterface = Cont
return controls;
}

public onFormUpdate(formUpdate: FormUpdate<FormInterface>): void {}

/**
* Extend this method to provide custom local FormGroup level validation
*/
Expand Down Expand Up @@ -348,17 +346,6 @@ export abstract class NgxSubFormComponent<ControlInterface, FormInterface = Cont
value: unknown;
}

const formControlNames: (keyof FormInterface)[] = Object.keys(this.formControlNames) as (keyof FormInterface)[];

const formValues: Observable<KeyValueForm>[] = formControlNames.map(key =>
this.formGroup.controls[key].valueChanges.pipe(
startWith(this.formGroup.controls[key].value),
map(value => ({ key, value })),
),
);

const lastKeyEmitted$: Observable<keyof FormInterface> = merge(...formValues.map(obs => obs.pipe(map(x => x.key))));

this.subscription = this.formGroup.valueChanges
.pipe(
// hook to give access to the observable for sub-classes
Expand All @@ -370,9 +357,7 @@ export abstract class NgxSubFormComponent<ControlInterface, FormInterface = Cont
// be changed once the children are being initialized
delay(0),
filter(() => !!this.formGroup),
// detect which stream emitted last
withLatestFrom(lastKeyEmitted$),
map(([_, keyLastEmit], index) => {
map((_, index) => {
if (index > 0 && this.onTouched) {
this.onTouched();
}
Expand All @@ -390,10 +375,6 @@ export abstract class NgxSubFormComponent<ControlInterface, FormInterface = Cont
),
);
}

const formUpdate: FormUpdate<FormInterface> = {};
formUpdate[keyLastEmit] = true;
this.onFormUpdate(formUpdate);
}
}),
)
Expand Down
4 changes: 0 additions & 4 deletions projects/ngx-sub-form/src/lib/ngx-sub-form.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ import { FormControl, FormGroup, ValidationErrors } from '@angular/forms';
import { Observable } from 'rxjs';
import { ArrayPropertyKey, ArrayPropertyValue, Controls, FormUpdate } from './ngx-sub-form-utils';

export interface OnFormUpdate<FormInterface> {
onFormUpdate?: (formUpdate: FormUpdate<FormInterface>) => void;
}

type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
type Nullable<T> = T | null;

Expand Down