Bonjour,

je bosse sur des formulaires assez complexe et j'ai des FormArray contenant des Formgroup que je voudrais binder grâce à des ControlValueAccessor dans les sous-composants.

Malheureusement seul le premier composant est bindé et j'ai une erreur :
core.js:6456 ERROR TypeError: control.registerOnChange is not a function
at setUpModelChangePipeline (forms.js:1700)
at setUpControl (forms.js:1530)
at FormGroupDirective.addControl (forms.js:5224)
at FormControlName._setUpControl (forms.js:5806)
at FormControlName.ngOnChanges (forms.js:5751)
at FormControlName.rememberChangeHistoryAndInvokeOnChangesHook (core.js:1498)
at callHook (core.js:2536)
at callHooks (core.js:2495)
at executeInitAndCheckHooks (core.js:2446)
at refreshView (core.js:9456)
core.js:28040 Angular is running in development mode. Call enableProdMode() to enable production mode.
core.js:6456 ERROR TypeError: control.registerOnChange is not a function
at setUpModelChangePipeline (forms.js:1700)
at setUpControl (forms.js:1530)
at FormGroupDirective.addControl (forms.js:5224)
at FormControlName._setUpControl (forms.js:5806)
at FormControlName.ngOnChanges (forms.js:5751)
at FormControlName.rememberChangeHistoryAndInvokeOnChangesHook (core.js:1498)
at callHook (core.js:2536)
at callHooks (core.js:2495)
at executeInitAndCheckHooks (core.js:2446)
at refreshView (core.js:9456)
index.js:52 [WDS] Live Reloading enabled.
Biazarrement si je modifie une valeur dans l'interface le deuxième se bind bien, voici un exemple de code simplifier à l'extreme

App.component.html:
Code html : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
<form [formGroup]="form">
  <input type="text" formControlName="page">
  <ng-container formArrayName="users">
    <ng-container *ngFor="let item of users.controls;index as i">
      <app-form-user [formControlName]="i">
      </app-form-user>
    </ng-container>
  </ng-container>
 
</form>
 
{{form.value|json}}
<!-- <router-outlet></router-outlet> -->

le .ts
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Component } from '@angular/core';
import { FormArray, FormControl, FormGroup } from '@angular/forms';
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'form-array';
  form = new FormGroup({
    page: new FormControl("home"),
    users: new FormArray([
      new FormGroup({ name: new FormControl("toto"), age: new FormControl(15) }),
      new FormGroup({ name: new FormControl("jaja"), age: new FormControl(25) })
    ])
  });
 
  get users(): FormArray {
    return this.form.get('users') as FormArray;
  }
}
mon form-user.html :
Code html : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
<form [formGroup]="formGroup">
    <input type="text" formControlName="name">
    <input type="number" formControlName="age">
</form>

le .ts
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import { Component, forwardRef, OnInit } from '@angular/core';
import { ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
 
@Component({
  selector: 'app-form-user',
  templateUrl: './form-user.component.html',
  styleUrls: ['./form-user.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => FormUserComponent),
      multi: true
    }
  ]
})
export class FormUserComponent implements OnInit, ControlValueAccessor {
 
  formGroup = new FormGroup({
    name: new FormControl(),
    age: new FormControl()
  });
 
  onChange: (value: any) => void = () => { };
  onTouch: any = () => { }
 
  constructor() { }
 
  writeValue(obj: any): void {
    this.formGroup.setValue(obj);
  }
  registerOnChange(fn: any): void {
    this.formGroup.valueChanges.subscribe(fn);
  }
  registerOnTouched(fn: any): void {
    this.onTouch = fn;
  }
 
  ngOnInit(): void {
  }
 
}

Sur internet je trouve principalement des exemples de formarray qui n'héberge pas de sous composant, j'ai pas vu d'exemple similaire au mien ...

Merci pour votre aide