Skip to content

Commit

Permalink
fix(lib): access class properties from getFormControls method
Browse files Browse the repository at this point in the history
BREAKING CHANGE: If you have components that are extending one of the classes of ngx-sub-form AND that have an `ngOnInit` hook, they should call `super.ngOnInit()`

This closes #82
  • Loading branch information
maxime1992 committed Nov 12, 2019
1 parent 1956d25 commit b3a93db
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 7 deletions.
2 changes: 2 additions & 0 deletions projects/ngx-sub-form/src/lib/ngx-root-form.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export abstract class NgxRootFormComponent<ControlInterface, FormInterface = Con
protected dataValue: ControlInterface | null = null;

public ngOnInit(): void {
super.ngOnInit();

// we need to manually call registerOnChange because that function
// handles most of the logic from NgxSubForm and when it's called
// as a ControlValueAccessor that function is called by Angular itself
Expand Down
7 changes: 7 additions & 0 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 @@ -77,6 +77,7 @@ class SubComponentWithDefaultValues extends NgxSubFormComponent<Vehicle> {
describe(`Common`, () => {
it(`should call formGroup.updateValueAndValidity only if formGroup is defined`, (done: () => void) => {
const subComponent: SubComponent = new SubComponent();
subComponent.ngOnInit();

const formGroupSpy = spyOn(subComponent.formGroup, 'updateValueAndValidity');

Expand All @@ -96,8 +97,11 @@ describe(`NgxSubFormComponent`, () => {

beforeEach((done: () => void) => {
subComponent = new SubComponent();
subComponent.ngOnInit();
debouncedSubComponent = new DebouncedSubComponent();
debouncedSubComponent.ngOnInit();
subComponentWithDefaultValues = new SubComponentWithDefaultValues();
subComponentWithDefaultValues.ngOnInit();

// we have to call `updateValueAndValidity` within the constructor in an async way
// and here we need to wait for it to run
Expand Down Expand Up @@ -512,6 +516,7 @@ describe(`NgxSubFormComponent`, () => {

beforeEach((done: () => void) => {
validatedSubComponent = new ValidatedSubComponent();
validatedSubComponent.ngOnInit();

// we have to call `updateValueAndValidity` within the constructor in an async way
// and here we need to wait for it to run
Expand Down Expand Up @@ -580,6 +585,7 @@ describe(`NgxSubFormRemapComponent`, () => {

beforeEach((done: () => void) => {
subRemapComponent = new SubRemapComponent();
subRemapComponent.ngOnInit();

// we have to call `updateValueAndValidity` within the constructor in an async way
// and here we need to wait for it to run
Expand Down Expand Up @@ -685,6 +691,7 @@ describe(`SubArrayComponent`, () => {

beforeEach((done: () => void) => {
subArrayComponent = new SubArrayComponent();
subArrayComponent.ngOnInit();

// we have to call `updateValueAndValidity` within the constructor in an async way
// and here we need to wait for it to run
Expand Down
20 changes: 13 additions & 7 deletions projects/ngx-sub-form/src/lib/ngx-sub-form.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OnDestroy } from '@angular/core';
import { OnDestroy, OnInit } from '@angular/core';
import {
AbstractControl,
AbstractControlOptions,
Expand Down Expand Up @@ -28,7 +28,7 @@ type MapControlFunction<FormInterface, MapValue> = (ctrl: AbstractControl, key:
type FilterControlFunction<FormInterface> = (ctrl: AbstractControl, key: keyof FormInterface) => boolean;

export abstract class NgxSubFormComponent<ControlInterface, FormInterface = ControlInterface>
implements ControlValueAccessor, Validator, OnDestroy, OnFormUpdate<FormInterface> {
implements OnInit, ControlValueAccessor, Validator, OnDestroy, OnFormUpdate<FormInterface> {
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 @@ -69,10 +69,11 @@ export abstract class NgxSubFormComponent<ControlInterface, FormInterface = Cont
// when developing the lib it's a good idea to set the formGroup type
// to current + `| undefined` to catch a bunch of possible issues
// see @note form-group-undefined
public formGroup: TypedFormGroup<FormInterface> = (new FormGroup(
this._getFormControls(),
this.getFormGroupControlOptions() as AbstractControlOptions,
) as unknown) as TypedFormGroup<FormInterface>;
// formGroup will only be defined after ngOnInit
// otherwise it's impossible to access class properties
// from the `getFormControls` method which is an issue with validators
// see https://github.com/cloudnc/ngx-sub-form/issues/82
public formGroup!: TypedFormGroup<FormInterface>;

protected onChange: Function | undefined = undefined;
protected onTouched: Function | undefined = undefined;
Expand All @@ -81,7 +82,12 @@ export abstract class NgxSubFormComponent<ControlInterface, FormInterface = Cont

private subscription: Subscription | undefined = undefined;

constructor() {
public ngOnInit(): void {
this.formGroup = (new FormGroup(
this._getFormControls(),
this.getFormGroupControlOptions() as AbstractControlOptions,
) as unknown) as TypedFormGroup<FormInterface>;

// if the form has default values, they should be applied straight away
const defaultValues: Partial<FormInterface> | null = this.getDefaultValues();
if (!!defaultValues) {
Expand Down

0 comments on commit b3a93db

Please sign in to comment.