强制子输入具有与包装/父控件相同的“状态”

时间:2019-06-04 16:51:49

标签: angular angular-material

Stackblitz

如何将CustomInputComponent的{​​{3}}反映到<input id="childInput">的{​​{1}}内部的template的ngModel /控件中。

我想要这样做的原因是因为我有一个复杂的模板驱动验证器,我想在CustomInputComponent上进行设置,但是状态“错误,被触摸等...”也应适用于CustomInputComponent内部的嵌套输入。

我希望我能在这里实现目标。

在Stackblitz中,您将看到:

如果我输入“ 43”:

  • “父控件有效:”状态为CustomInputComponent
  • 但是“子输入有效:”状态仍然为false

编辑:

我添加了一个具有更复杂的模板驱动验证的案例:(即:仅当inp1和inp2是偶数时,父控件才有效)

STATE

它有效,但我必须添加以下行:(当然我需要退订!)

true

parentModel.control.statusChanges.subscribe( _ => this.ngModel.control.updateValueAndValidity() ); 中,以便仅更改inp1和inp2时才更新子输入!

1 个答案:

答案 0 :(得分:1)

您应该在子组件中获取父ngModel和子ngModel的引用,然后合并验证器。不幸的是,因为使用NG_VALUE_ACCESSOR,所以必须使用Injector来获取父模型:

working example #1

export class CustomInputComponent implements ControlValueAccessor { 
  @ViewChild(NgModel, { static: false }) ngModel: NgModel; 

  constructor(private _renderer: Renderer2, readonly injector: Injector) {}

  ngAfterViewInit(): void {
    const parentModel = this.injector.get(NgModel);

    this.ngModel.control.setValidators([
      this.ngModel.control.validator,
      parentModel.validator
    ]);

    this.ngModel.control.updateValueAndValidity();
  }
}

如果您有任何异步验证器,则应对这些验证器重复相同的过程

如果您不想使用Injector,则可以通过在构造函数中而不是在装饰程序中进行设置来使组件使用NG_VALUE_ACCESSOR。不幸的是,然后在setTimeout中就需要一个ngAfterViewInit,因为该钩子是父项而不是父项(而不是ngOnInit),并且验证器尚未正确设置:

working example #2

@Component({
  selector: 'app-custom-input',
  templateUrl: './custom-input.component.html',
  styleUrls: ['./custom-input.component.css']
})
export class CustomInputComponent implements ControlValueAccessor {
  @ViewChild('inputElement', {static: false}) private _inputElement: ElementRef;
  get inputElement(): ElementRef {
    return this._inputElement;
  }

  @ViewChild(NgModel, { static: false }) ngModel: NgModel; 

  constructor(private _renderer: Renderer2, @Self() readonly parentModel: NgModel) {
     this.parentModel.valueAccessor = this;
  }

  ngAfterViewInit(): void {
    setTimeout(() => {
      this.ngModel.control.setValidators([
        this.ngModel.control.validator,
        this.parentModel.control.validator
      ]);
      this.ngModel.control.updateValueAndValidity();
    }) 
  }
}