user5289740
user5289740

Reputation:

Angular validator will not be destroyed

I use a component with reactive form in a tab. Each time when I switch the tab, the validator of my component will be called once more. This is my component:

import { Component, forwardRef, OnInit } from "@angular/core";
import {
  AbstractControl,
  FormBuilder,
  FormGroup,
  NG_VALIDATORS,
  NG_VALUE_ACCESSOR,
  ValidationErrors,
  Validator,
  Validators
} from "@angular/forms";

@Component({
  selector: "app-my-form",
  templateUrl: "./my-form.component.html",
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => MyFormComponent),
      multi: true
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => MyFormComponent),
      multi: true
    }
  ]
})
export class MyFormComponent implements Validator, OnInit {
  public form: FormGroup;
  constructor(fb: FormBuilder) {
    this.form = fb.group({
      name: [null, Validators.required]
    });
  }

  // ControlValueAccessor
  public writeValue(value: any): void {
    if (value) {
      this.form.patchValue(value, { emitEvent: false });
    }

    if (value === null) {
      this.form.reset();
    }
  }

  public registerOnChange(fn: any): void {
    this.form.valueChanges.subscribe(fn);
  }

  public registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  public setDisabledState?(isDisabled: boolean): void {
    isDisabled ? this.form.disable() : this.form.enable();
  }
  // ControlValueAccessor end

  // Validator
  validate(control: AbstractControl): ValidationErrors {
    console.log("validate");
    return null;
  }
  // Validator end

  public onTouched: () => void = () => {};

  ngOnInit() {}
}

I also made a stackblitz: https://stackblitz.com/edit/angular-tab-test-hx71jy?file=src%2Fapp%2Fmy-form%2Fmy-form.component.ts

what am I doing wrong?

Upvotes: 1

Views: 601

Answers (1)

Chellappan வ
Chellappan வ

Reputation: 27471

The issue is because of memory leak in formControlName directive. As a workaround you can set destroyOnHide input property to false, so that it will hide the component instead of destroying.

<form [formGroup]="form">
  <ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs">
    <li [ngbNavItem]="1" [destroyOnHide]="false">
      <a ngbNavLink>One</a>
      <ng-template ngbNavContent>
        <app-my-form formControlName="tab1"></app-my-form>
      </ng-template>
    </li>
    <li [ngbNavItem]="2">
      <a ngbNavLink>Two</a>
      <ng-template ngbNavContent>
        <p>
          Lorem ipsum
        </p>
      </ng-template>
    </li>
  </ul>
</form>

Upvotes: 1

Related Questions