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
