Weboldal keresés

javascript - Angular: egyéni input a ControlValueAccessor használatával


Nem vagyok biztos benne, hogyan tudok egy egyedi komponenst használni, ha az egy másik komponens alatt van becsomagolva.

Like :

ComponentA_withForm
|
--ComponentA1_withWrapperOfCustomInput
  |
  --ComponentA11_withCustomInput

ha van egy ilyen szerkezetem:

ComponentA_withForm
|
--ComponentA11_withCustomInput

Minden rendben

De az én esetemben (rengeteg aszinkron adat) szükségem van egy csomagolóra... Vajon valahogy lehetséges ezt megtenni?

Itt van a fiddle kódom:

KomponensA :

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) { }
}

KomponensA1:

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

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

KomponensA11:

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) => { };
}

És itt van egy működő minta: https://stackblitz.com/edit/angular-qmrj3a

Szóval: alapvetően a CustomInputWrapperComponent használata nélküli kód eltávolítása és átalakítása miatt működik a kódom. De szükségem van erre a wrapperre, és nem vagyok biztos benne, hogyan lehetne akkor átadni a formControlName-t.

Nem akarok egy piszkos megoldást azzal, hogy továbbadom a szülő formGroup-ot :)

Válasz #1

Mivel nem akarsz egy piszkos megoldást ;) , egyszerűen implementálhatod a ControlValueAccessor-t a CustomInputWrapperComponent-ben is. Így a szülőben történt bármilyen változás a gyermekben is meg fog jelenni, a gyermekben történt változás pedig a szülőben is visszatükröződik néhány sor kód segítségével.

Csomagoló komponens

@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) => { };
}

Szülő sablon

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

Készítettem egy stackbitz demót itt - https://stackblitz.com/edit/angular-csaxcz

Válasz #2

nem használhatja a formControlName-t a custom-input-wrapper-en, mert az nem valósítja meg a ControlValueAccessor-t. A ControlValueAccessor megvalósítása a custom-input-wrapper-en lehetne megoldás, de túlbonyolítottnak tűnik. Ehelyett adja át a kontrollt a formGroup-ból a custom-input-wrapper-nek @Input()-ként, és adja tovább a bevitt formControl-t a custom-input-nak

app.komponens

@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) { }
}

egyéni-bemenet-csomagoló.komponens

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

itt van egy működő demo https://stackblitz.com/edit/angular-3lrfqv

Kapcsolódó cikkek