[SalesForce] LWC use querySelectorAll to get all ids associated with checked checkboxes in the view, and update the Database

My goal is onclick of any checkbox here, get the data-id of all checked activities. I've tried several things, but new to LWC and fairly new to selectors.

Currently, when I click any checkbox, the last 4 lines in the Console here print. In my reading, it seems that SecureNodeList may not be traversable.

[![enter image description here][1]][1]


<template>
  <lightning-card>
  <h3 slot="title">
      <lightning-icon icon-name="utility:connected_apps" size="small"></lightning-icon>
      Activities
  </h3>
  <div class="slds-m-left_medium slds-m-right_medium slds-text-medium">
    Remember to click Save after checking off activities. Once all Mandated Activities 
    have been checked off, you may Submit to your manager.
  </div>

  <div slot="footer">
    <!-- Neutral variant (default) -->
    <lightning-button label="Save" onchange={selectAllCheckedOffActivities} class="slds-m-left_x-small"></lightning-button>
    <!-- Neutral variant (default) -->
    <lightning-button label="Submit" title="Non-primary action" onclick={handleClick} class="slds-m-left_x-small"></lightning-button>
  </div>


    <div class="slds-m-left_medium slds-m-top_medium slds-m-bottom_medium">
      <div class="slds-text-heading_medium">Mandated Activities</div>
      <template for:each={mandatedActivities} for:item="activity">
          <span key={activity.id}>
            <div class="slds-col">
                <lightning-input type="checkbox" data-id={activity.id} label={activity.title} checked={activity.isChecked}></lightning-input>
            </div>
          </span>
      </template>
      <div class="slds-text-heading_medium slds-m-top_medium">If Appropriate</div>
      <template for:each={ifAppropriateActivities} for:item="activity">
        <span key={activity.id}>
          <div class="slds-col">
              <lightning-input type="checkbox" data-id={activity.id} label={activity.title} checked={activity.isChecked}></lightning-input>
          </div>
        </span>
      </template>
      <div class="slds-text-heading_medium slds-m-top_medium">Optional Activities</div>
      <template for:each={optionalActivities} for:item="activity">
        <span key={activity.id}>
          <div class="slds-col">
              <lightning-input type="checkbox" data-id={activity.id} label={activity.title} checked={activity.isChecked}></lightning-input>
          </div>
        </span>
      </template>
    </div>
  </lightning-card>
</template>

import {LightningElement, wire, track} from 'lwc';
import {CurrentPageReference} from 'lightning/navigation';
import getEventActivityWrappers from '@salesforce/apex/EventActivities_Ctrl.getEventActivityWrappers';
import updateEventActivityCheckboxTracker from '@salesforce/apex/EventActivities_Ctrl.updateEventActivityCheckboxTracker';

export default class EventActivityChecklist extends LightningElement {

  @track currentPageReference = null;
  @track siteSurveyId = '';
  @track activityIdsForTracker = 'a1e1k00000Fvv6TAAR,a1e1k00000Fvv6UAAR,a1e1k00000Fvv6dAAB';

  @track activities = [];
  @track mandatedActivities = [];
  @track ifAppropriateActivities = [];
  @track optionalActivities = [];

  @track checkedBoxesIds = [];

  @wire(CurrentPageReference) getRecordIdFromURL(currentPageReference) {
      if (currentPageReference) {
        this.siteSurveyId = currentPageReference.attributes.recordId;
      }
  }
  
  get selectedIds() {
    return this.checkedBoxesIds.join(',');
  }
  
  selectAllCheckedOffActivities(event) {
    this.checkedBoxesIds = [...this.template.querySelectorAll('lightning-input')].filter(element => element.checked).map(element => element.dataset.id);
    console.log('*** checkedBoxesIds: ' + this.checkedBoxesIds);
  }

  @wire(updateEventActivityCheckboxTracker, {siteSurveyId: '$siteSurveyId', checkedBoxesIds:'$checkedBoxesIds'}) wiredUpdateOfCheckboxTracker({ data, error }) {
    console.log('*** checkedBoxesIds: ' + this.checkedBoxesIds);
  }
  
  @wire(getEventActivityWrappers, {siteSurveyId:'$siteSurveyId'}) 
    wiredGetEventActivityWrappers({data, error}) {
      if (data) {
        console.log(data);
        this.activities = data;
        if(this.activities) {
          this.activities.forEach((activity) => {
            if(activity.type == "Mandated Activity") {
              this.mandatedActivities.push(activity);
            } else if(activity.type == "If Appropriate") {
              this.ifAppropriateActivities.push(activity); 
            } else if(activity.type == "Optional Activity") {
              this.optionalActivities.push(activity); 
            }
          })
        }
      } else if (error) {
        console.log(error);
      }
    }
}

public with sharing class EventActivities_Ctrl {
  
  @AuraEnabled (cacheable=true)
  public static void updateEventActivityCheckboxTracker(String siteSurveyId, String activityIdsForTracker) {
    System.debug('*** siteSurveyId: ' + siteSurveyId);
    System.debug('*** activityIdsForTracker: ' + activityIdsForTracker);

    Site_Survey__c siteSurvey = [SELECT Id, Event_Activity_Checkbox_Tracker__c
                                 FROM Site_Survey__c 
                                 WHERE Id = :siteSurveyId];
    siteSurvey.Event_Activity_Checkbox_Tracker__c = activityIdsForTracker;
    update siteSurvey;

    System.debug('***Tracker from DB: ' + [SELECT Id, Event_Activity_Checkbox_Tracker__c
                                        FROM Site_Survey__c 
                                        WHERE Id = :siteSurveyId]);
  }

  @AuraEnabled (cacheable=true)
  public static List<EventActivityWrapper> getEventActivityWrappers(String siteSurveyId) {
    List<EventActivityWrapper> eventActivityWrappers = new List<EventActivityWrapper>();
    List<Event_Activity__c> eventActivities = [SELECT Id, Title__c, Type__c 
                                               FROM Event_Activity__c 
                                               ORDER BY Type__c ASC];
    Site_Survey__c siteSurvey = [SELECT Id, Event_Activity_Checkbox_Tracker__c
                                        FROM Site_Survey__c 
                                        WHERE Id = :siteSurveyId];

    for(Event_Activity__c eventActivity: eventActivities) {
      EventActivityWrapper eventActivityWrapper = new EventActivityWrapper(eventActivity.Id, 
                                                                           eventActivity.Title__c, 
                                                                           eventActivity.Type__c, 
                                                                           false);

      for(String activityIdFromTracker : siteSurvey.Event_Activity_Checkbox_Tracker__c.split(',')){
        if(activityIdFromTracker == eventActivity.Id){
          eventActivityWrapper.isChecked = true;
        }
      }
      eventActivityWrappers.add(eventActivityWrapper);
    }
    return eventActivityWrappers;
  }

  public class EventActivityWrapper{
        
    @AuraEnabled
    public Id activityId{get;set;}
    @AuraEnabled
    public String title{get;set;}
    @AuraEnabled
    public String type{get;set;}
    @AuraEnabled
    public Boolean isChecked{get;set;}

    public EventActivityWrapper(String activityId, String title, String type, Boolean isChecked) {
      this.activityId = activityId;
      this.title = title;
      this.type = type;
      this.isChecked = isChecked;
    }
  }
}

Best Answer

You can query the elements, filter by the checkbox, and then grab the data you want. This is pretty trivial:

this.checkedBoxesIds = [...this.template.querySelectorAll('lightning-input')]
  .filter(element => element.checked)
  .map(element => element.dataset.id);

Where [...iterable] copies an array or array-like element into a proper Array, Array.filter checks the condition and returns only the matching elements, and Array.map translates an array into another array (by "mapping" the value).