Search code examples
angularvalidationinputangular-reactive-formsreusability

angular create input component reusable


I am creating a reusable text component with validator

export class CompInputComponent implements OnInit{
  @Input() controlFormGroup: FormGroup;
  @Input() controlLabel: string;
  @Input() controlPlaceHolder: string;
  @Input() controlName: string;
  @Input() errorMessage: string;
  private _isRequired = false;

  @Input()
  get isRequired(): boolean {
    return this._isRequired;
  }
  set isRequired(val: boolean) {
    this._isRequired = coerceBooleanProperty(val);
  }

  @Output() onComponentReady: EventEmitter<FormGroup> = new EventEmitter<FormGroup>();
  
  constructor(private fb: FormBuilder) { }
  
  ngOnInit(){
    console.log(this.isRequired);
    if(this.isRequired){
      console.log(this.isRequired);

      this.controlFormGroup.addControl(this.controlName, new FormControl('', Validators.required));
    }else{
      this.controlFormGroup.addControl(this.controlName, new FormControl(''));
    }

    this.onComponentReady.emit(this.controlFormGroup);
  }
}

<div [formGroup]="controlFormGroup">
    <mat-form-field appearance="outline">
        <mat-label>{{controlLabel}}</mat-label>
        <input matInput [placeholder]="controlPlaceHolder" [formControlName]="controlName" />
        <mat-error *ngIf="controlFormGroup.controls.controlName.hasError('required')">">
            <span [innerHTML]="errorMessage"></span>
        </mat-error>
    </mat-form-field>
</div>

My problem is that I can’t set up the mat-error. I have the following error:

core.js:5967 ERROR TypeError: Cannot read property 'hasError' of undefined at CompInputComponent_Template

The name of the control is not hard but also dynamic


Solution

  • this should work, you are creating your form controls dynamically, it means they doesn't exist at the beginning. you need to check if the form control created.

       export class CompInputComponent implements OnInit{
          @Input() controlFormGroup: FormGroup;
          @Input() controlLabel: string;
          @Input() controlPlaceHolder: string;
          @Input() controlName: string;
          @Input() errorMessage: string;
          private _isRequired = false;
        
          @Input()
          get isRequired(): boolean {
            return this._isRequired;
          }
          set isRequired(val: boolean) {
            this._isRequired = coerceBooleanProperty(val);
          }
        
          @Output() onComponentReady: EventEmitter<FormGroup> = new EventEmitter<FormGroup>();
          
          constructor(private fb: FormBuilder) { }
          
          ngOnInit(){
            console.log(this.isRequired);
            if(this.isRequired){
              console.log(this.isRequired);
        
              this.controlFormGroup.addControl(this.controlName, new FormControl('', Validators.required));
            }else{
              this.controlFormGroup.addControl(this.controlName, new FormControl(''));
            }
        
            this.onComponentReady.emit(this.controlFormGroup);
          }
        }
        
        <div [formGroup]="controlFormGroup">
            <mat-form-field appearance="outline">
                <mat-label>{{controlLabel}}</mat-label>
                <input matInput [placeholder]="controlPlaceHolder" [formControlName]="controlName" />
                <mat-error *ngIf="!!controlFormGroup.controls.controlName && controlFormGroup.controls.controlName.hasError('required')">">
                    <span [innerHTML]="errorMessage"></span>
                </mat-error>
            </mat-form-field>
        </div>