Как распространять валидаторы и стили CSS для управления вводом внутри пользовательского компонента формы Angular? - PullRequest
2 голосов
/ 10 июля 2019

У меня есть вложенный компонент формы с полем <input>, настроенным для работы с formControlName="nested". Валидаторы установлены на родительском FormControl, например:

  form = this.fb.group({
    value: ['', [Validators.required, Validators.minLength(3)]],
    nested: ['', [Validators.required, Validators.minLength(3)]],
  });

Я хочу передать статус от родительского FormControl к вложенному <input>, чтобы он реагировал так же, как обычный, не вложенный <input>, , т. Е. , только при прикосновении к нему. и нажав «отправить» (что делает control.markAsTouched()), статус устанавливается на «НЕДЕЙСТВИТЕЛЬНО», а стиль CSS ng-invalid устанавливается.

Мне удалось получить частичный выигрыш после прочтения этой публикации SO со следующим кодом, который подписывается на изменения статуса родительского элемента управления, но "касание" вложенного ввода вернет значение VALID и нажатие кнопки «Отправить» не установит стиль ng-invalid.

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

private isAlive = true;

constructor(@Optional() @Self() public ngControl: NgControl, private cdr: ChangeDetectorRef) {
    if (this.ngControl != null) {
        this.ngControl.valueAccessor = this;
    }
}

ngAfterViewInit(): void {
    this.ngControl.statusChanges.pipe(
        takeWhile(() => this.isAlive)
    ).subscribe(status => {
        console.log('Status changed: ', status, 'Errors: ', this.ngControl.errors);
        this.tbNgModel.control.setErrors(this.ngControl.errors);
        this.cdr.detectChanges();
    });

    this.ngControl.control.updateValueAndValidity(); // to force emit initial value
}

Stackblitz воспроизведение моей проблемы

Как я могу по-настоящему распространить статус на вложенный элемент управления, все это при установке валидаторов только на родительский элемент FormControl?

1 Ответ

1 голос
/ 10 июля 2019

Dstj, все должно быть проще.смотрите stackblitz

, просто в нашем входе мы можем использовать [ngClass]

<input [ngClass]="{'ng-touched':ngControl.control.touched,'ng-invalid':ngControl.control.invalid}" 
type="text" class="form-control" [(ngModel)]="value" 
       (ngModelChange)="propagateChange($event)"
       (blur)="touched()"
 > 

, где ngControl - это инъекция ngControl в конструкторе

constructor(@Self() public ngControl: NgControl) {
        if (this.ngControl != null) {
            this.ngControl.valueAccessor = this;
        }
    }

См., Что это ngControl, который действителен / недействителен или не затронут ....

Обновлено добавить (размытие), чтобы пометить как прикосновение

Обновлено2 с использованием ngDoCheck

Используется другое решение ngDoCheck,

Наш компонент

  value: string;
  customClass=null;
  onChange:boolean=false;

    constructor(@Self() public ngControl: NgControl,private el:ElementRef) {
        if (this.ngControl != null) {
            this.ngControl.valueAccessor = this;
        }
    }
  ngDoCheck()
  {
    if (!this.onChange)
    {
      this.onChange=true;
      //it's necesary a setTimeOut to give Angular a chance
      setTimeout(()=>{
        this.customClass=this.el.nativeElement.getAttribute('class');
        this.onChange=false;
      })
    }
  }
  change(value:any)
  {
    this.propagateChange(value);
    this.touched(null)
  }

.html

<input #tbNgModel="ngModel" [ngClass]="customClass" type="text" class="form-control" 
     [(ngModel)]="value" 
     (ngModelChange)="change($event)" 
     (blur)="touched()"> 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...