Угловой: пользовательский ввод с ControlValueAccessor - PullRequest
2 голосов
/ 19 июня 2019

Я не уверен, как я могу использовать пользовательский компонент, если он является оболочкой другого компонента.

Например:

ComponentA_withForm
|
--ComponentA1_withWrapperOfCustomInput
  |
  --ComponentA11_withCustomInput

, если у меня есть такая структура:

ComponentA_withForm
|
--ComponentA11_withCustomInput

Все хорошо

Но для моего случая (тонны асинхронных данных) мне нужна оболочка ... Можно ли как-нибудь это сделать?

Вот мой код скрипты:

Компонент A:

import { Component } from '@angular/core';
import { FormBuilder } from '@angular/forms';

@Component({
  selector: 'my-app',
  template: `<form [formGroup]="form"><custom-input-wrapper formControlName="someInput"></custom-input-wrapper></form> <p>value is: {{formVal | json}}</p>`
})
export class AppComponent {
  form = this.fb.group({
    someInput: [],
  });

  get formVal() {
    return this.form.getRawValue();
  }

  constructor(private fb: FormBuilder) { }
}

Компонент A1:

import { Component } from '@angular/core';

@Component({
  selector: 'custom-input-wrapper',
  template: '<custom-input></custom-input>',
})
export class CustomInputWrapperComponent {
  constructor() { }
}

Компонент A11:

import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'custom-input',
  template: `Hey there! <button (click)="inc()">Value: {{ value }}</button>`,
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => CustomInputComponent),
    multi: true,
  }],
})
export class CustomInputComponent implements ControlValueAccessor {

  private value = 0;

  writeValue(value: number): void {
    this.value = value;
  }

  registerOnChange(fn: (_: any) => void): void {
    this.onChangeFn = fn;
  }

  registerOnTouched(fn: any): void {
  }

  inc() {
    this.value = this.value + 1;
    this.onChangeFn(this.value);
  }

  onChangeFn = (_: any) => { };
}

И вот у меня есть рабочий образец: https://stackblitz.com/edit/angular-qmrj3a

так: в основном удаление и рефакторинг кода без использования CustomInputWrapperComponent делает мой код работающим.Но мне нужна эта обертка, и я не уверен, как передать formControlName тогда.

Я не хочу грязного решения с передачей родительского formGroup:)

Ответы [ 2 ]

1 голос
/ 19 июня 2019

вы не можете использовать formControlName на custom-input-wrapper, потому что он не реализует ControlValueAccessor. реализация ControlValueAccessor на custom-input-wrapper может быть решением, но это кажется излишним. Вместо этого передайте элемент управления из formGroup в custom-input-wrapper как @Input() и передайте введенный formControl в custom-input

app.component

@Component({
  selector: 'my-app',
  template: `<form [formGroup]="form"><custom-input-wrapper [formCtrl]="form.get('someInput')"></custom-input-wrapper></form> <p>value is: {{formVal | json}}</p>`
})
export class AppComponent {
  form = this.fb.group({
    someInput: [],
  });

  get formVal() {
    return this.form.getRawValue();
  }

  constructor(private fb: FormBuilder) { }
}

заказ ввод-wrapper.component

@Component({
  selector: 'custom-input-wrapper',
  template: '<custom-input [formControl]="formCtrl"></custom-input>',
})
export class CustomInputWrapperComponent {
  @Input() formCtrl: AbstractControl;
  constructor() { }
}

вот рабочая демоверсия https://stackblitz.com/edit/angular-3lrfqv

1 голос
/ 19 июня 2019

Поскольку вы не хотите грязного решения;), вы можете просто реализовать ControlValueAccessor в CustomInputWrapperComponent. Таким образом, любое изменение в родительском элементе будет отражено в дочернем элементе, любое изменение в дочернем элементе также будет отражено в родительском элементе с помощью всего лишь нескольких строк кода.

Компонент обертки

@Component({
  selector: 'custom-input-wrapper',
  template: '<custom-input [formControl]="value"></custom-input>',
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => CustomInputWrapperComponent),
    multi: true,
  }]
})
export class CustomInputWrapperComponent implements AfterViewInit, ControlValueAccessor  {
  public value = new FormControl();

  constructor() { }

  ngAfterViewInit() {
    this.value.valueChanges.subscribe((x) => {
      this.onChangeFn(x);
    });
  }

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

  registerOnChange(fn: (_: any) => void): void {
    this.onChangeFn = fn;
  }

  registerOnTouched(fn: any): void {
  }

 onChangeFn = (_: any) => { };
}

Родительский шаблон

<form [formGroup]="form"><custom-input-wrapper formControlName="someInput"></custom-input-wrapper></form> <p>value is: {{formVal | json}}</p>

Я сделал здесь демонстрацию стакбита - https://stackblitz.com/edit/angular-csaxcz

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