3

I need to develop a reusable list component, which returns a list of objects, a plain list of objects, those should be a assigned to key in a formGroup object value.

Is there a way to do a custom control in Angular which is a list?

Here is what I tried and what I intent to do, hope the code is self explanatory.

// PARENT COMPONENT 
<div [formGroup]="form" [ngSubmit]="submit()">
    <custom-list formControlName="profiles"></custom-list>
    <custom-list formControlName="groups"></custom-list>
    <custom-list formControlName="users"></custom-list>

    <button>Submit</button>
</div>

@Component(...)
export class ParentComponent implements OnInit {
    form: FormGroup;

    constructor(private _formBuilder: FormBuilder) {
        // Method One
        this.form = this._formBuilder.group({
          profiles: ['', Validators.required],
          groups: ['', Validators.required],
          users: ['', Validators.required]
        });

        // Method Two. Don't know how is should be or if it will work?
        this.form = this._formBuilder.group({
          profiles: this._formBuilder.array([]),
          groups: this._formBuilder.array([]),
          users: this._formBuilder.array([])
        });
    }
}

Then the child (the list component is defined as this)

// CHILD COMPONENT
@Component({
  selector: 'custom-list',
  providers: [{
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CustomListComponent),
      multi: true
  }]
})
export class CustomListComponent implements OnInit, ControlValueAccessor { 
    form: FormGroup;

    constructor(private _formBuilder: FormBuilder) {
        this.form = this._formBuilder.group({
          elements: this._formBuilder.array([], Validators.required)
        });
    }

    writeValue(val: any): void {
        val && this.form.setControl('elements', this._formBuilder.array(val));
    }
}

The form value should looks like this

{
    profiles: [{id: 1, name: "profile 1"}, {id: 2, name: "profile 2"}],
    groups: [{id: 1, name: "group 1"}, {id: 2, name: "group 2"}],
    users: [{id: 1, name: "user 1"}, {id: 2, name: "user 2"}]
}

Doing it that way it worked, BUT the list added an extra key to the form group keys, which is the group I added to the child form.

{
        profiles: { 
           elements: [{id: 1, name: "profile 1"}, {id: 2, name: "profile 2"}] 
           },
        groups: { 
           elements: [{id: 1, name: "group 1"}, {id: 2, name: "group 2"}]
           },
        groups: { 
           elements: [{id: 1, name: "user 1"}, {id: 2, name: "user 2"}] 
          }
    }
1

1 Answer 1

3

extended my comment, stackblitz Your children

    <div *ngFor="let group of myFormArray.controls;let i=index" [formGroup]="group">
        <input formControlName="prop1">
    <div *ngIf="group.get('prop1').invalid">Prop1 Required</div>
    <input formControlName="prop2"/>
    <div *ngIf="group.get('prop2').invalid">Prop2 Required</div>
  @Input()myFormArray:FormArray

Your parent

<div [formGroup]="form" [ngSubmit]="submit()">
    <custom-list [myFormArray]="form.get('profiles')"></custom-list>
    <custom-list [myFormArray]="form.get('groups')></custom-list>
    <custom-list [myFormArray]="form.get('users')></custom-list>

    <button>Submit</button>
</div>
Sign up to request clarification or add additional context in comments.

2 Comments

that looks pretty good. Let me give it a try. In fact there is no need for ControlValueAccessor to be used
Be carefully, there are an error in the in the stackblitz , the @Input() myArray:string must be @Input() myArray:FormArray

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.