Angular ControlValueAccessor и markAsTouched - PullRequest
1 голос
/ 03 мая 2020

Я использую angular 9 с Angular Material, и у меня есть пользовательский элемент управления, реализующий интерфейс ControlValueAccessor. Все работает нормально.

Во всех моих кнопках отправки, когда форма недействительна, я вызываю formGroup.markAllAsTouched, потому что все поля angular материала становятся красными. Таким образом, пользователь может лучше понять, какие элементы управления недопустимы.

Мне нужно реализовать то же поведение с моим пользовательским элементом управления. Как это сделать?

Я создал проект stackblitz, чтобы лучше понять ситуацию здесь

Ответы [ 3 ]

3 голосов
/ 03 мая 2020

Существует нет встроенных функций для передачи статуса touched во внутренний FormControl пользовательского элемента управления.

Ваш простой вариант - проверка состояния в ngDoCheck и один раз пользовательский элемент управления становится тронутым статус обновления для внутреннего FormControl:

ngDoCheck() {
  if (this.formControl.touched) {
    return;
  }
  if (this.controlDir.control.touched) {
    this.formControl.markAsTouched();
  }
}

Forked Stackblitz

Лично мне не нравятся подобные реализации с ControlValueAccessor. Я бы предпочел использовать тот же FormControl. Это можно сделать, добавив viewProviders с ControlValueAccessor провайдером в свой пользовательский элемент управления:

custom-control.component.ts

@Component({
  selector: 'my-custom-control',
  template: `
    <mat-form-field id="userType">
      <mat-label>My Custom Component</mat-label>
      <mat-select [formControlName]="controlName" (blur)="onTouched()">
        <mat-option *ngFor="let current of userTypes" [value]="current.id">{{current.name}}</mat-option>
      </mat-select>
    </mat-form-field>

  `,
   viewProviders: [{
    provide: ControlContainer,
    useFactory: (container: ControlContainer) => container,
    deps: [[new SkipSelf(), ControlContainer]],
 }]
})
export class MyCustomControl {
  @Input() controlName: string;

  userTypes: LookupModel[] = [
      new LookupModel(1, 'first'),
      new LookupModel(2, 'second')
  ];
}

parent html

<form [formGroup]="form">
  <my-custom-control controlName="userTypeCustomControl"></my-custom-control>

Пример Stackblitz

0 голосов
/ 05 мая 2020

Другой шанс - использовать следующий подход

Пользовательский код управления

@Component({
  selector: 'cvl-advertising-type',
  templateUrl: './advertising-type.component.html',
  styleUrls: ['./advertising-type.component.scss'],
})
export class AdvertisingTypeComponent implements OnInit, ControlValueAccessor {
  advertisingTypes: ReadonlyArray<LookupModel>;

  onChange = (value: number) => {
  };
  onTouched = () => {
  };

  constructor(private lookupService: LookupService,
              @Self() public controlDir: NgControl) {
    controlDir.valueAccessor = this;
  }

  ngOnInit(): void {
    this.advertisingTypes = this.lookupService.advertisingTypes;
  }

  registerOnChange(fn: (value: number) => void): void {
    this.controlDir.control.valueChanges.subscribe(fn);
    this.onChange = fn;
  }

  writeValue(value: number): void {
    this.controlDir.control.setValue(value);
    this.onChange(value);
  }

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

  setDisabledState(isDisabled: boolean): void {
    if (isDisabled) {
      this.controlDir.control.disable();
    } else {
      this.controlDir.control.enable();
    }
  }
}

и родительский html бланк

<cvl-advertising-type [formControl]="form.controls.advertisingType"></cvl-advertising-type>

Я нашел это решение после просмотра этого видео

Последняя, ​​но не менее важная проблема заключается в том, что я не понимаю, как проверить его с помощью поверхностного теста, потому что у меня следующая ошибка

Error: NodeInjector: NOT_FOUND [NgControl]
0 голосов
/ 03 мая 2020

Вы можете отметить this.controlDir.touched в хуке doCheck Lifecycle.

  ngDoCheck() {
    if (this.controlDir.touched) {
      this.formControl.markAsTouched();
    }
  }

Также вы должны создать личное поле в компоненте для кэша.

Пример здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...