ExpressionChangedAfterItHasBeenCheckedError при добавлении валидатора в ngOnInit

Я пытаюсь добавить пользовательский валидатор к входу, но когда я это делаю, он вызывает ошибку ExpressionChangedAfterItHasBeenCheckedError, сообщающую, что что-то изменилось с ИСТИНЫ на ЛОЖЬ.

Я проследил проблему до строки ниже:

ngOnInit(): void {
    this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()]));
}

Если я удалю TabValidator.ipaddress(), то ошибка исчезнет. Точно так же, если мой валидатор принудительно возвращает 'null', то ошибка исчезает. Мой валидатор выглядит следующим образом:

private static _ipaddress(address: string): any {
    console.log('checking ip address: '+address+' valid: '+ip.isV4Format(address)+' is null: '+(address === null ? 'yes' : 'no'));
    if (!ip.isV4Format(address)) { return { 'wrongFormat': true }; }
    console.log('returning null');
    return null;
}
public static ipaddress(): ValidatorFn {
    return (control: AbstractControl): { [key: string]: any } => {
        console.log('validator returning: '+TabValidator._ipaddress(control.value));
        return TabValidator._ipaddress(control.value);
    };
}

Из журнала консоли видно, что валидатор каждый раз возвращает одно и то же значение.

Может кто-нибудь объяснить, что здесь происходит не так? Я не могу объяснить, какая переменная меняется с "true" на "false", так как в приведенных выше строках нет логических значений. Как валидатор может возвращать разные значения, не появляясь в моем журнале консоли?

Я прочитал ТАК вопросы о том, как не делать что-то в ngOnInit, но это похоже на красную сельдь.


ОБНОВЛЕНИЕ: я попробовал:

ngOnInit(): void {
    Promise.resolve().then(() => {
    this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()]));
    });
}

а также

ngOnInit(): void {
  setTimeout(() => this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()])), 10);
}

но тогда ошибка изменится на:

ОШИБКА Ошибка: не удается найти элемент управления с именем: "шлюз"


РЕШЕНИЕ:

Я проследил это до ошибки - используя реактивные формы + валидаторы + вкладки ngb. Добавление валидатора к элементу управления на вкладке вызывает ошибку. Единственное решение - перейти на шаблонные формы.

1 ответ

Решение

Если вы посмотрите на страницу Angular на github Issues, вы можете найти пару билетов, связанных с той же проблемой, что и у вас (например, https://github.com/angular/angular/issues/15634, есть и другие, этот я только что нашел в качестве примера). Короче говоря: angular не нравится изменение вида в некоторых (всех?) Хуках жизненного цикла. Что именно меняется в вашем конкретном случае: я предполагаю, что это состояние действительности formField (то есть внутренне в управляющем коде Angular, к которому у вас нет доступа), которое внутренне вызывает обнаружение изменений...

Если это возможно для вас, двигайтесь this.ipv4Fields.addControl() для конструктора. Если это невозможно - см. Предложения в билетах GitHub (сделать detectChanges, или же Promise, или же setTimeout, так далее.)...

ОБНОВИТЬ:

@Component(){}
export class MyComponent implements OnInit{

    @Input()
    ipv4Fields: FormGroup;

    //inject `ChangeDetecorRef`
    constructor(protected changeDetectorRef: ChangeDetectorRef){
    }

    ngOnInit(){
         this.ipv4Fields.addControl('gateway', new FormControl('', [TabValidator.ipaddress()]));
         this.chageDetectorRef.detectChanges();
    }
}
Другие вопросы по тегам