@fattan
программист

Как в Angular custom control вывести весь список ошибок контрола?

Создаю кастомный контрол (с ControlValueAccessor и тд), руководствуясь статьёй: https://blog.angular-university.io/angular-custom-...

Хочу чтобы в этом контролле выводились все ошибки валидации, даже внешние, но на деле внутри контролла списка ошибок вообще нет.

Пример кода: https://stackblitz.com/edit/ng-custom-control-err?...

Фактические поведение:

60e82dbdf3590223792493.png

Ожидаемое:

component1 err: { "required": true }
component1 val: ""
component2 err: { "required": true }
component2 val: ""


Фактические поведение:

60e82de3eea73399362069.png

Ожидаемое:

component1 err: { "customErr": "customErr" }
component1 val: "e"
component2 err: { "customErr": "customErr" }
component2 val: "e"


Как заставить компонент кастомного контрола показыавть ошибки самого formControl?

На всякий случай,
код приложения


CustomControlComponent:

import { Component, forwardRef, OnDestroy, OnInit } from '@angular/core';
import {
  ControlValueAccessor,
  FormBuilder,
  FormControl,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
  ValidationErrors,
  Validator
} from '@angular/forms';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-custom-control',
  templateUrl: './custom-control.component.html',
  styleUrls: ['./custom-control.component.css'],
    providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CustomControlComponent),
      multi: true
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => CustomControlComponent),
      multi: true,
    }
  ],
})
export class CustomControlComponent
  implements OnInit, OnDestroy, ControlValueAccessor, Validator {
  control = this.fb.control(null);

  private onTouched = () => {};

  private readonly ngUnsubscribe$ = new Subject<void>();

  constructor(
    private fb: FormBuilder
  ) {}

  ngOnInit() {}

  ngOnDestroy() {
    this.ngUnsubscribe$.next();
    this.ngUnsubscribe$.complete();
  }

  registerOnChange(onChange: (value: string | null) => void) {
    this.control.valueChanges
    .pipe(
        takeUntil(this.ngUnsubscribe$)
    )
    .subscribe(onChange);
  }

  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  writeValue(outsideValue: string | null) {
    if (outsideValue) {
      this.control.setValue(outsideValue, { emitEvent: false });
    }
  }

  setDisabledState(disabled: boolean) {
    if (disabled) {
      this.control.disable();
    } else {
      this.control.enable();
    }
  }

  validate(c: FormControl): ValidationErrors | null {
    const value = this.control.value;

    const error = value === 'e';

    return error ? { customErr: 'customErr' } : null;
  }
}

<div>component2 err: {{control?.errors | json}}</div>
<div>component2 val: {{control?.value | json}}</div>

<input [formControl]="control" class="text-control" />


AppComponent:

<div>component1 err: {{control?.errors | json}}</div>
<div>component1 val: {{control?.value | json}}</div>

<hr>

<app-custom-control [formControl]="control"></app-custom-control>


import { Component, VERSION } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  control = new FormControl(null, Validators.required);
}


  • Вопрос задан
  • 31 просмотр
Решения вопроса 1
Xuxicheta
@Xuxicheta Куратор тега Angular
инженер
Потому что ваш компонент, реализующий ControlValueAccessor , знать ничего не знает про ошибки в контроле формы. Он вообще про этот контрол ничего не знает, связующим звеном тут служит директива formControl, которая слушает контрол и при внешнем изменении его вызывает writeValue.

Можно сделать свою еще директиву которая будет вызывать другой метод, типа setErrors, но стандартной такой функции нет.
Вот в этой статье можно найти похожую реализацию, только там передаются pristine и touched. https://habr.com/ru/post/491062/

Или проще, просто передать ошибки внутрь через инпут :)
А чтобы наоборот, перекинуть внутренние ошибки на верхний контрол нужно реализовать Validator
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы