Фактическая проблема здесь заключается в том, что установка валидаторов снаружи нарушает концепцию неизменности. Входные данные - это объект, в котором изменяется только свойство внутри этого объекта. Angular не регистрирует это как изменение.
Интересно, что это не просто проблема с ChangeDetction.OnPush. Используя обнаружение изменений по умолчанию, angular обновляет представление, потому что проверяются все компоненты, но если вы зарегистрируетесь в ловушке жизненного цикла onChanges, вы заметите, что фактическое изменение не зарегистрировано в ловушке жизненного цикла ни в одной из конфигураций обнаружения изменений. Поэтому будьте осторожны: кажется, что он работает только с обнаружением изменений по умолчанию, но работает не полностью. Поэтому будьте осторожны, чтобы помнить об изменчивости объекта независимо от используемого вами обнаружения изменений.
Сказав, что: в вашем случае, следуя SoC, я бы на самом деле переместил установку валидатора внутри компонента ввода, в зависимости от логического свойства ввода, вместо установки валидатора извне. В дополнение к SoC это также имело бы преимущество в том, что в случае наличия других валидаторов, которые могут понадобиться вашему компоненту ввода, вы фактически располагаете все те в одном месте и можете сбросить их, как только захотите удалить требуемый валидатор, поскольку, насколько я знаю нет возможности удалить конкретный валидатор (пока).
Ваш input.component.ts
будет выглядеть примерно так (учтите, что это всего лишь псевдокод):
input.component.ts
export class InputComponent implements OnChanges {
@Input() required: boolean;
@Input() control: FormControl;
ngOnChanges(simpleChanges: SimpleChanges){
if(simpleChanges.required) {
if(simpleChanges.required.nextValue) {
this.control.addValidator(...)
} else {
this.control.clearValidators()
}
}
}
}
В случае, если установка валидатора внутри вашего ввода вообще не является опцией по какой-либо причине, вам на самом деле нужно будет вызвать changeDetection вручную. Для этого я бы сделал следующее:
app.component.ts
constructor(private fb: FormBuilder, private ref: ChangeDetectorRef) {}
toggleValidator() {
if (this.requiredTrue) {
this.requiredTrue = false;
this.formGroup.get('agreed').clearValidators();
// this is important
this.formGroup.get('agreed').updateValueAndValidity();
} else {
this.requiredTrue = true;
this.formGroup.get('agreed').setValidators(Validators.requiredTrue)
// this is important
this.formGroup.get('agreed').updateValueAndValidity();
}
console.log(this.formGroup);
}
input.component.ts
constructor(private ref: ChangeDetectorRef) {
}
ngOnInit() {
this.control.valueChanges.subscribe(() => {
this.ref.markForCheck();
});
}
Взгляните на это stackblitz