【问题标题】:How to override the custom component value in reactive form in angular如何以角度的反应形式覆盖自定义组件值
【发布时间】:2021-09-17 23:48:25
【问题描述】:

我有一个自定义的响应式表单组件,它具有三个输入。日、月和年。该组件按预期工作,除非我希望在父级中通过 formControlName.value 访问自定义值。

在我的父母中; 代码

this.form = new FormGroup({date_of_birth: new FormControl(null, [Validators.required])});

html

<dashboard-custom-date formControlName="date_of_birth"></dashboard-custom-date>

在我拥有的自定义组件中;

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

@Component({
  selector: 'dashboard-custom-date',
  templateUrl: './custom-date.component.html',
  styleUrls: ['./custom-date.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CustomDateComponent),
      multi: true
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => CustomDateComponent),
      multi: true
    }
  ]
})
export class CustomDateComponent implements OnInit, ControlValueAccessor, Validator {

  dateOfBirth: FormGroup;
  errorMessages = {
    day: [
      { type: 'required', message: '* Day is required' },
      { type: 'min', message: '* Day must be between 1-31 and a valid day' },
      { type: 'max', message: '* Day must be between 1-31 and a valid day' }
    ],
    month: [
      { type: 'required', message: '* Month is required' },
      { type: 'min', message: '* Month must be between 1-12 and a valid month' },
      { type: 'max', message: '* Month must be between 1-12 and a valid month' }
    ],
    year: [
      { type: 'required', message: '* Year is required' },
    ],
  };
  public onTouched: () => void = () => { };
  constructor() { }
  ngOnInit() {
    this.dateOfBirth = new FormGroup(
      {
        day: new FormControl(null, [Validators.required, Validators.min(1), Validators.max(31)]),
        month: new FormControl(null, [Validators.required, Validators.min(1), Validators.max(12)]),
        year: new FormControl(null, [Validators.required])
      }
    );
  }
  IsFieldValid(field: string, error: any) {
    return this.dateOfBirth?.get(field).hasError(error.type) && this.IsInvalid(field);
  }
  IsInvalid(field: string) {
    const { dirty, touched, invalid } = this.dateOfBirth?.get(field);
    return (invalid && (dirty || touched));
  }
  IsValid(field: string): boolean {
    const { valid, dirty, touched } = this.dateOfBirth?.get(field);
    return valid && (dirty || touched);
  }
  writeValue(val: any): void {
    // tslint:disable-next-line:no-unused-expression
    val && this.dateOfBirth.setValue(val, { emitEvent: false });
  }
  registerOnChange(fn: any): void {
    console.log('on change');
    this.dateOfBirth.valueChanges.subscribe(fn);
  }
  registerOnTouched(fn: any): void {
    console.log('on blur');
    this.onTouched = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    isDisabled ? this.dateOfBirth.disable() : this.dateOfBirth.enable();
  }
  validate(c: AbstractControl): ValidationErrors | null {
    console.log('Date Of birth validation', c.value);
    return this.dateOfBirth.valid ? null : { invalidForm: { valid: false, message: 'date of birth fields are invalid' } };
  }

 // custom value
  value() {
    return 'custom value';
  }
}

所以在父组件中,当我写入值时,它应该返回我应该是“自定义值”的自定义组件值,但是,现在它不会返回那个值。

因此,使用父级中的 formControlName.value,我应该能够访问子级的自定义值。由于孩子有三个输入,我只想输出一个自定义值。

console.log(this.form.controls.date_of_birth.value); //should return custom value of the child, but doesn't

但是,现在它返回{day: 'day input value', month: 'month input value', year: 'year input value'}

【问题讨论】:

    标签: angular angular-reactive-forms ionic5


    【解决方案1】:

    如果您需要访问FormGroup 中任何FormControl 的值,您可以使用自己的方式访问它,即this.form.controls['date_of_birth'].value

    但是,如果您需要访问子组件的任何属性/功能,您应该创建一个新的template variable 并通过使用ViewChild 装饰器创建一个变量从组件类中访问它,如下所示:

    parent.component.html

    <dashboard-custom-date
      #customDateRef
      formControlName="date_of_birth"
    ></dashboard-custom-date>
    

    parent.component.ts

    @ViewChild('customDateRef', { read: CustomDateComponent })
    customDate: CustomDateComponent; // Now you can access any pbulic property/function using this variable
    
    onSubmit() {
      console.log(this.customDate.value());
      // Now this should return `custom value` of the child.
    }
    

    但是,您始终可以使用registerOnChange 方法注册的onChange 函数,将表单控件的值更改为任何其他自定义值,因此您必须更改子组件,如下所示:

    dashboard-custom-date.component.ts

    onChange: any = () => {};
    
    ngOnInit() {
      // ....
    
      // move the valueChanges subscription to the ngOnInit instead of using it directly within registerOnTouched method
      // use `onChange` method to push the changes to the form-control
      this.dateOfBirth.valueChanges.subscribe(this.onChange);
    }
    
    registerOnChange(fn: any): void {
      this.onChange = fn;
    }
    
    pushCustomValueToFormControl() {
      // Always you can use `onChange` method to push any other values to the form-control like the following:
      this.onChange('custom value');
    }
    

    【讨论】:

    • 这对我的情况没有帮助,因为父级的 formGroup 中还有其他键。所以我正在为父表单中的所有 formControlName 键寻找通用方式。我在父键(11 个键)上有 for 循环。我在这里只添加了一个自定义组件。
    • 我正在父 formGroup 中应用自定义验证器,我正在根据 foreach 循环中的 formControlName.value 进行决定。
    • 如果您想从 formControlName.value 访问任何内容,您必须将其包含在子组件的值中。
    • 我无法获得最后一条评论。这就是我正在研究如何覆盖或获取应该是我在孩子中的自定义值的 formControlName.value?
    • 你的意思是你需要在表单控件的值中包含额外的属性,而不仅仅是孩子的 formGroup 的值?
    猜你喜欢
    • 1970-01-01
    • 2020-03-11
    • 2017-10-06
    • 2021-02-08
    • 1970-01-01
    • 2021-07-20
    • 1970-01-01
    • 2019-10-30
    • 2018-07-31
    相关资源
    最近更新 更多