function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
ethanoneethanone 

How to dynamically populate lightning checkbox group?

I’m trying to build a LWC that displays a checkbox group created from the list of active users in the same sales market as the current user.

Html file (based on component reference):
<template>
        <lightning-checkbox-group name="Checkbox Group"
                                label="Select a User"
                                options={comms}
                                value={value}
                                onchange={handleChange}>
        </lightning-checkbox-group>
        <p>Selected Values are: {selectedValues}</p>
</template>
js file:
import { LightningElement, api, track, wire } from "lwc";
import getMktUsers from "@salesforce/apex/Top100.getMktUsers";
import getCommissions from "@salesforce/apex/Top100.getCommissions";
import Id from "@salesforce/user/Id";

let url_string = window.location.href;
let url = new URL(url_string);
let rid = url.searchParams.get("Id");

export default class Top100 extends LightningElement {
  @api recordId;
  @api objectApiName;
  @api userId;
  @track value = ["Option1"];
  userId = Id;
  recordId = rid;

  @wire(getMktUsers, { usrId: "$userId" }) MktUsers;
  @wire(getCommissions, { rid: "$recordId" }) selectedVals;

  objectApiName = "lda_Opportunity__c";

  get comms() {
    return [{ label: "Ross", value: "Option1" }, { label: "Rachel", value: "Option2" }];
  }

  get selectedValues() {
    return this.value.join(",");
  }

  handleChange(e) {
    this.value = e.detail.value;
  }
}
Apex file:
public with sharing class Top100 {
    @AuraEnabled(cacheable=true)
    public static List<Account> getMktUsers(Id usrId) {
        User ThisUser = [SELECT Id, Name, Office__c FROM User WHERE Id = :usrId LIMIT 1];
        List<User> MarketUsers = [SELECT Id FROM User WHERE Office__c = :ThisUser.Office__c and IsActive = True];
        //Users have matching Person accounts because some opportunities involve external sales people.
        return [SELECT Id, Name, FirstName, LastName FROM Account WHERE UserLookup__c IN :MarketUsers];
    }

    @AuraEnabled(cacheable=true)
    public static List<String> getCommissions(Id rid){
        List<String> values = new List<String>();
        for (lda_Commission__c comm : [SELECT Agent__c, Agent__r.Name FROM lda_Commission__c WHERE DealId__c = :rid]){
            values.add(comm.Agent__c);
        }
        System.debug('Values: ' + values);
        return values;
    }
}
1) How do I take the results of my Apex function and format it for the checkbox group options parameter?
2) How do I take the results of my getCommissions Apex function and format it for the checkbox group value parameter?



 
Alain CabonAlain Cabon
@ethanone

That could be easier with a function instead of a property for the wired parts.

myWiredMktUsers below is a free name for the function and it is automatically linked with the @wire annotation just above.

The function myWiredMktUsers has always a fixed object parameter with the error (result of the getMktUsers) and the returned data.
@track mktUsers;
@track error;

@wire(getMktUsers, { usrId: "$userId" })
    myWiredMktUsers({ error, data }) {
        if (data) {
            this.mktUsers = data;
            this.error = undefined;
            // other initializations using "value" for instance based on the data
        } else if (error) {
            this.error = error;
            this.mktUsers = undefined;
        }
    }

https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.data_wire_service_about

 
ethanoneethanone
I'm missing something. I tried what you described above and then am I supposed to set my checkbox options={mktUsers}? That gives me a checkbox with no labels or values. Somehow that data needs to get into the format { label: "Ross", value: "Option1" } doesn't it?
Alain CabonAlain Cabon
That is not sufficient indeed. It is just the idea.

In fact, you must convert mktUsers into "value" but I don't know your data.
for (let i=0; i < mktUsers.length; i++) {
      console.log('mktUsers:' + JSON.stringify(mktUsers[i]);
}
What do you see in the console log?  

Chrome:   Open the Console panel to view logged messages or run JavaScript
Press Command+Option+J (Mac) or Control+Shift+J (Windows, Linux, Chrome OS) to jump straight into the Consolepanel.
 
ethanoneethanone
its logging as a value pair
{"Id":"001a000001U8h9Zxxx","Name":"John Smith"}
But I assume it needs to indexes need to be "label" and "value" and I'm not sure how to access the values to rewrite it.
 
ethanoneethanone
I'll try that. I did something similar, without success:
@track MktUsers = [];

  @wire(getMktUsers, { usrId: "$userId" })
  myWiredMktUsers({ error, data }) {
    if (data) {
        data.forEach(function(element){
            let objvar = { label: element["Name"], value: element["Id"] };
            this.MktUsers.push(objvar);
        });
      this.error = undefined;
    } else if (error) {
      this.error = error;
      this.MktUsers = undefined;
    }
  }
I guess I can't push directly into my tracked variable?
Did you put that in to the myWiredMktUsers function or into the get comms function or is that outside of either?
ethanoneethanone
Got it! Thank you! Final looked like this:
export default class Top100 extends LightningElement {
  @api userId;
  @track value = ["Option1"];
  @track MktUsers = [];
  @track error;
  userId = Id;

  @wire(getMktUsers, { usrId: "$userId" })
    myWiredMktUsers({ error, data }) {
      if (data) {
        this.MktUsers = data;
        this.error = undefined;
      } else if (error) {
        this.error = error;
        this.MktUsers = undefined;
      }
    }

  get comms() {
    let alist = [];
    this.MktUsers.forEach(function(element) {
      alist.push({ label: element["Name"], value: element["Id"] });
    });
    return alist;
  }

  get selectedValues() {
    return this.value.join(",");
  }

  handleChange(e) {
    this.value = e.detail.value;
  }
}

 
Alain CabonAlain Cabon
So finally,    @wire(getMktUsers, { usrId: "$userId" })  MktUsers,   and your code:
get comms() {
    let alist = [];
    this.MktUsers.forEach(function(element) {
      alist.push({ label: element["Name"], value: element["Id"] });
    });
    return alist;
  }
... at the beginning could work directly (shortest form).

The only interesting thing is to get "error" maybe.
 
ethanoneethanone
I tried dropping the error/data callback on the wired function and it didn't work. hmm, i'll try it again, perhaps I had a typo. Thanks again for your help
Alain CabonAlain Cabon
Ok, if you had a solution, that is enough.

Otherwise, re-check the content of MktUsers (perhaps different).
 
for (let i=0; i < MktUsers.length; i++) {
      console.log('MktUsers:' + JSON.stringify(MktUsers[i]));
}
ethanoneethanone
I finally got back to this project. To continue, the user will select other team members with the checkboxes and the component will then create or delete a series of child records based on the selected users. Is there some documentation on bulkifying the creation and the deletion? I can't imagine its acceptable to just forEach a bunch of createRecord() function calls. Will the createRecord function take a list of record inputs? Can I assume that the same bulkification pattern for createRecord will work on the deleteRecord() function?

I'm currently looping through the selected checkboxes and performing a createRecord and while it creates the records, none of the toasts display.
ethanoneethanone
In retrospect, my question was based on the the VF way of thinking. Since a user can only check/uncheck on box at a time, i suppose i can just create/delete real-time as they check the boxes. I suppose there will be a future use case for bulkifying CRUD actions in LWC, so might still be relevant to answer (editable data tabels?), but not for this one.