Заставить дочерний ввод иметь те же «состояния», что и для переноса / родительского контроля - PullRequest
0 голосов
/ 04 июня 2019

Stackblitz

Как я могу отразить STATE из CustomInputComponent в ngModel / элемент управления <input id="childInput"> внутри template из CustomInputComponent.

Причина, по которой я этого хочу, заключается в том, что у меня есть сложные валидаторы, управляемые шаблонами, которые я хочу установить (например,) CustomInputComponent, но состояния «ошибка, касание и т. Д.» Должны бытьтакже примените к вложенным входам внутри CustomInputComponent.

Я надеюсь, что ясно, что я пытаюсь достичь здесь.

В Stackblitz, как вы увидите:

Если я наберу «43»:

  • «Родительский элемент управления действителен:»: false.
  • Но состояние «дочерний ввод действителен:» остается true.

Редактировать:

Я добавил случай с более сложной проверкой на основе шаблонов: (то есть родительский элемент управления действителен только тогда, когда inp1 и inp2 являются четными числами)

новый Stackblitz .

Это работает, но мне пришлось добавить строку: (конечно, мне нужно отписаться!)

parentModel.control.statusChanges.subscribe(
  _ => this.ngModel.control.updateValueAndValidity()
);

в ngAfterViewInit, тактот дочерний ввод обновляется, когда изменяются только inp1 и inp2!

1 Ответ

1 голос
/ 07 июня 2019

Вы должны получить ссылку родительского элемента ngModel и дочернего элемента ngModel в дочернем компоненте, а затем объединить валидаторы. К сожалению, поскольку вы используете NG_VALUE_ACCESSOR, вы должны использовать Injector, чтобы получить родительскую модель:

рабочий пример # 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), и валидатор еще не будет установлен правильно:

рабочий пример # 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();
    }) 
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...