2

I'm trying to create a form where I can add checkboxes dynamically based on the data received from API. I successfully received the data in JSON format as below

[
{
    "code": "TicketTypeRead",
    "name": "Read Ticket Types"
},
{
    "code": "BatchRead",
    "name": "Read Batches"
},
{
    "code": "BatchWrite",
    "name": "Create Batches"
},
{
    "code": "TopupWrite",
    "name": "Add Topups"
},
{
    "code": "ValidationWrite",
    "name": "Can Do Validation"
}

]

Based on this data I want to add checkboxes on the page using Reactive form approach in Angular. What I tried is I create a FormGroup like below

constructor(private router: Router,
    private fb: FormBuilder,
    private route: ActivatedRoute,
    private _deviceService: DeviceService) { }

 this.deviceForm = this.fb.group({
        apiKey: '',
        chariotId: [null, numberOnly],
        deviceUID: ['', Validators.required],
        //enabled:true,
        name: ['', Validators.required],
        bearer: ['', Validators.required],
        sotiId: null,
        permissions: this.fb.array([])
    })

and when I received the data from service, tried to add it in permissions FormArray as below. But this doesn't show anything on the page.

onPermissionsRetrieved(permissions: IPermissions[]):void
{
    var items = this.deviceForm.get('permissions') as FormArray;
    for (let permission of permissions)
    {
        items.push(this.buildPermission(permission.code, permission.selected));
    }
}

I can see the FormGroup value which is:

    value:{ "apiKey": "", 
"chariotId": null, 
"deviceUID": "", 
"name": "", 
"bearer": "", 
"sotiId": null, 
"permissions": [ { "code": "TicketTypeRead", "selected": null }, 
{ "code": "BatchRead", "selected": null }, 
{ "code": "BatchWrite", "selected": null }, 
{ "code": "TopupWrite", "selected": null }, 
{ "code": "ValidationWrite", "selected": null } ] }

Any suggestions what is missing? I'm using Angular 4.4.4

EDIT: template code looks like this

<div class="form-group">
            <label class="control-label">Permissions</label>
            <div formArrayName="permissions" *ngFor="let permission of permissions.controls; let i=index">
                <input formControlName="code" type="checkbox" id="{{permission.code}}" />
                <label>{{permission.name}}</label>
            </div>
        </div>
Nouman Bhatti
  • 1,341
  • 6
  • 28
  • 54

1 Answers1

1

You are missing some pieces of your code. You need to include formGroupName in your template and also your attempt to show your formcontrols are a bit off. So your TS code would look something like this:

onPermissionsRetrieved():void {
  var items = this.deviceForm.get('permissions') as FormArray;
  for (let permission of this.permissions) {
    items.push(this.fb.group({
      code: permission.code,
      name: permission.name
    }))
  }
}

and your template:

<div class="form-group" [formGroup]="deviceForm">
  <label class="control-label">Permissions</label>
  <!-- mark the formArray first -->
  <div formArrayName="permissions">
    <!-- here add the formGroupName, which is the index -->
    <div  *ngFor="let permission of deviceForm.controls.permissions.controls; let i=index" [formGroupName]="i">
      <input formControlName="code" type="checkbox" id="{{permission.code}}" />
        <!-- use 'value' in between, since the 'name' is inside that object -->
        <label>{{permission.value.name}}</label>
    </div>      
  </div>
</div>

DEMO: http://plnkr.co/edit/Da87V6Mc4HfVRKJToxC7?p=preview

Here of course all checkboxes will be checked initially, since the code exists in all. If you are not looking for this (which I assume) you need to add some boolean value instead, which would initially be set as false, so something like this for example: http://plnkr.co/edit/k7GpVxuyVDDd8UFkKGzn?p=preview With this you can also track which checkbox is checked and which not based on that boolean value.

Alternatively you can do something like this: https://stackoverflow.com/a/43424244/6294072 where you insert the value to the formArray when the checkbox is checked, that way you get only the values that are checked.

AT82
  • 71,416
  • 24
  • 140
  • 167