forms angular

forms - Angular: ControlValueAccessor compuesto para implementar el formulario anidado



(2)

Nosotros (en el trabajo) encontramos ese problema y probamos diferentes cosas durante meses: Cómo lidiar adecuadamente con los formularios anidados.

De hecho, ControlValueAccessor parece ser el camino a seguir, pero lo encontramos muy detallado y fue bastante largo construir formas anidadas. Como estamos usando mucho ese patrón dentro de nuestra aplicación, terminamos dedicando algo de tiempo a investigar e intentar encontrar una mejor solución. Lo llamamos ngx-sub-form y es un repositorio disponible en NPM (+ código fuente en Github ).

Básicamente, para crear un formulario secundario todo lo que tiene que hacer es extender una clase que proporcionamos y también pasar sus controles de formulario. Eso es.

Hemos actualizado nuestra base de código para usarla y definitivamente estamos contentos con ella, por lo que es posible que desee probar y ver cómo le va :)

Todo se explica en el Github .

PD: También tenemos una demostración completa ejecutándose aquí https://cloudnc.github.io/ngx-sub-form

La composición de ControlValueAccessor para implementar el formulario anidado se presenta en una presentación de Angular Connect 2017.

https://docs.google.com/presentation/d/e/2PACX-1vTS20UdnMGqA3ecrv7ww_7CDKQM8VgdH2tbHl94aXgEsYQ2cyjq62ydU3e3ZF_BaQ64kMyQa0INe2oI/pub?slide=id.g293d7d2b9d_1_1532

En esta presentación, el orador mostró una manera de implementar un control de formulario personalizado que tiene un valor múltiple (no solo un valor de cadena único sino que tiene dos campos de cadena, como calle y ciudad). Quiero implementarlo pero estoy atascado. La aplicación de muestra está aquí, ¿alguien sabe qué debo corregir?

https://stackblitz.com/edit/angular-h2ehwx

componente principal

@Component({ selector: ''my-app'', template: ` <h1>Form</h1> <form [formGroup]="form" (ngSubmit)="onSubmit(form.value)" novalidate> <label>name</label> <input formControlName="name"> <app-address-form formControlName="address"></app-address-form> <button>submit</button> </form> `, }) export class AppComponent { @Input() name: string; submitData = ''''; form: FormGroup; constructor(private fb: FormBuilder) { this.form = fb.group({ name: ''foo bar'', address: fb.group({ city: ''baz'', town: ''qux'', }) }); } onSubmit(v: any) { console.log(v); } }

componente de forma anidada

@Component({ selector: ''app-address-form'', template: ` <div [formGroup]="form"> <label>city</label> <input formControlName="city" (blur)="onTouched()"> <label>town</label> <input formControlName="town" (blur)="onTouched()"> </div> `, providers: [ { provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => AddressFormComponent) } ] }) export class AddressFormComponent implements ControlValueAccessor { form: FormGroup; onTouched: () => void = () => {}; writeValue(v: any) { this.form.setValue(v, { emitEvent: false }); } registerOnChange(fn: (v: any) => void) { this.form.valueChanges.subscribe(fn); } setDisabledState(disabled: boolean) { disabled ? this.form.disable() : this.form.enable(); } registerOnTouched(fn: () => void) { this.onTouched = fn; } }

y mensaje de error que recibí

ERROR TypeError: Cannot read property ''setValue'' of undefined at AddressFormComponent.writeValue (address-form.component.ts:32) at setUpControl (shared.js:47) at FormGroupDirective.addControl (form_group_directive.js:125) at FormControlName._setUpControl (form_control_name.js:201) at FormControlName.ngOnChanges (form_control_name.js:114) at checkAndUpdateDirectiveInline (provider.js:249) at checkAndUpdateNodeInline (view.js:472) at checkAndUpdateNode (view.js:415) at debugCheckAndUpdateNode (services.js:504) at debugCheckDirectivesFn (services.js:445)

Creo que la instancia de FormGroup debería inyectarse al componente de formulario anidado de alguna manera ...


Un par de problemas, en su AppComponent cambie su FormBuilder a:

this.form = fb.group({ name: ''foo bar'', address: fb.control({ //Not using FormGroup city: ''baz'', town: ''qux'', }) });

En su AddressFormComponent necesita inicializar su FormGroup de la siguiente manera:

form: FormGroup = new FormGroup({ city: new FormControl, town: new FormControl });

Aquí está el tenedor de su muestra: https://stackblitz.com/edit/angular-np38bi