Extends FormGroup and handling subscription inside

3k views Asked by At

I normally create my forms this way:

export class ModelXFormGroup extends FormGroup {
  constructor() {
    super({
      property1: new FormControl()
    });
  }

  getRawValue(): ModelX {
    return super.getRawValue();
  }

  patchValue(template: ModelX) {
    super.patchValue();
  }

  get property(): FormControl {
    return this.get('property') as FormControl;
  }

}

If I need to make a property "disabled" depending on other, then in the constructor I can do like:

this.property1.valueChanges(newValue -> {
     if(newValue){
          this.property2.disabled();
     } else{
          this.property2.enabled();
     }
});

But I don't know how I could I kill those subscriptions... I mean, I cannot use here ngOnDestroy and call this.subscription.unsubscribe().

Any way to do this inside the form?

Because the only alternative I'm thinking is like having a method in the form to unsuscribe manually all properties...

Component:

onDestroy {
    this.form.unSuscribe();
}

But I would like to make it transparent for the component..

2

There are 2 answers

6
deerawan On

You could use takeUntil

private _destroyed = new Subject<boolean>();


ngOnInit() {
 // property 1
 this.property1.valueChanges
  .pipe(
    takeUntil(this._destroyed) // specify takeUntil
  )
  .subscribe(value => { ... })

  // property 2
  this.property2.valueChanges
  .pipe(
    takeUntil(this._destroyed) 
  )
  .subscribe(value => { ... })
}   

ngOnDestroy() {
  this._destroyed.next(true); // will unsubscribe all property that specify takeUntil
  this._destroyed.unsubscribe();
}

If want to use valueChanges in the class, maybe we could create a specific subject in the class as a trigger for unsubscription

export class ModelXFormGroup extends FormGroup {
  private _formDestroyed = new Subject<boolean>();
  
  constructor() {
    super({
      property1: new FormControl()
    });

    this.property1.valueChanges
     .pipe(
       takeUntil(this._formDestroyed) // specify takeUntil
     )
     .subscribe(value => { ... })
  }

  getRawValue(): ModelX {
    return super.getRawValue();
  }

  patchValue(template: ModelX) {
    super.patchValue();
  }

  get property(): FormControl {
    return this.get('property') as FormControl;
  }

  // define a new method here for unsubscription
  unsubscribe() {
    this._formDestroyed.next(true);
    this._formDestroyed.unsubscribe();
  }

}

later in the component you could call this subject in ngOnDestroy

ngOnDestroy() {
  this.myModelXForm.unsubscribe();
}
0
Arigui Ahmed On

Hey I'm actually dealing always with this approach like 'MyNeedForm'. So for handling subscriptions in my class wich is extending FormGroup:

initialize first an Subscription array in the head of your class:

private subscriptions: Subscription[];

add your subscribe stuff inside, for eg:

const valueChangesControl = valueChangeControl.valueChanges.subscribe(x => console.log("Value: ", x));
this.subscriptions.push(valueChangesControl);

write your function to cut them all:

cutSubscribtions() {
  this.subscriptions.forEach(sub => sub.unsubscribe());
}

finaly in the OnDestroy() life cycle of your component where you instanciate your form, call the function:

ngOnDestroy() {
  console.log("call destroy()");
  this.testForm.cutSubscribtions();
}

Take a look on this example: https://stackblitz.com/edit/angular-ivy-5bzb6c?file=src/app/test.form.ts