I have written a custom LWC with some nested accordians. I have a function that expands all similarly named child accordion sections in the each of the parent accordion sections. I was able to get it to work in the Local Dev Server, but when I use it in an org it does not work. I am assuming because of Locker Service.
This method is where I find my issue (see full code below).
expandThisCardOnAll(event) {
var competitorList = this.allCompetitors;
var cardType = event.target.value;
var allAccordianElements = this.template.querySelectorAll('lightning-accordion');
var populateFirstAccordian = true; // this is a workaround that assumes the main accordian will always be first
allAccordianElements.forEach(function(thisAccordian) {
if(populateFirstAccordian){
populateFirstAccordian = false;
thisAccordian.activeSectionName = competitorList;
//
}
else {
thisAccordian.activeSectionName = cardType;
}
});
}
When I am in the dev server, and I log allAccordianElements to console it returns
[objectNodeList]
, but when I am in the org, it returns:
SecureNodeList: [object NodeList]{ key: {"namespace":"c"} }
I tried to access the elements through the wrapper, but no luck. I read some posts that say that it is not possible, but perhaps there is a way to access using a querySelector that I am not aware of.
Here is the HTML file...
<template>
<div class="slds-box slds-box_xx-small">
<div class="slds-clearfix">
<div class="slds-float_left slds-m-around_x-small">
<div class="slds-text-heading_medium">Competitive Intelligence Battlecards</div>
</div>
<div class="slds-float_right slds-m-around_x-small">
<lightning-button-group>
<lightning-button label="Collapse Competitors" onclick={collapseAllCompetitors}>
</lightning-button>
<lightning-button label="Collapse All" onclick={collapseAll}></lightning-button>
<lightning-button label="Refresh Data" onclick={refreshData}>
</lightning-button>
</lightning-button-group>
<lightning-button label="Open client" value={homepageClient} onclick={navigateToWebPage} variant="brand"
class="slds-var-m-left_x-small">
</lightning-button>
</div>
</div>
<template if:true={competitors}>
<lightning-accordion allow-multiple-sections-open active-section-name={expandedCompetitorSections}>
<template for:each={competitors} for:item="competitor">
<div key={competitor.Id} class="slds-box slds-box_xx-small slds-m-around_x-small">
<lightning-accordion-section key={competitor.Id} name={competitor.Name} label={competitor.Name}
class="slds-box_xx-small">
<lightning-button-menu slot="actions" alternative-text="Show menu" icon-size="x-small"
menu-alignment="right">
<lightning-menu-item value={competitor.Name} label="Email this Competitor Card"
icon-name="utility:open" onclick={emailContent}>
</lightning-menu-item>
<lightning-menu-item value={competitor.Client__c} label="View Competitor in Client"
icon-name="utility:open" onclick={navigateToWebPage}>
</lightning-menu-item>
<lightning-menu-item value={competitor.Client__c} label="Edit Competitor in Client"
icon-name="utility:edit" onclick={navigateToWebPage}>
</lightning-menu-item>
<lightning-menu-item value="CollapseAll" label="Collapse All"
icon-name="utility:collapse_all" onclick={collapseAll}></lightning-menu-item>
</lightning-button-menu>
<div class="slds-box slds-box_xx-small">
<lightning-card key={competitor.Id} title={competitor.Full_Company_Name__c}
icon-name="custom:custom63">
<div class="slds-card__body slds-card__body_inner">
<p key={competitor.Id}>
<lightning-formatted-url value={competitor.Company_Website__c}
tooltip="Go to competitor website" label={competitor.Company_Website__c}
target="_blank">
</lightning-formatted-url>
</p>
<p key={competitor.Id}>{competitor.Summary__c}</p>
</div>
</lightning-card>
</div>
<lightning-accordion allow-multiple-sections-open>
<template for:each={competitor.Battlecards__r} for:item="battlecard">
<lightning-accordion-section key={battlecard.Id} name={battlecard.Name}
label={battlecard.Name}>
<lightning-button-menu slot="actions" alternative-text="Show menu"
icon-size="x-small" menu-alignment="right">
<lightning-menu-item value={battlecard.Name} label="Email this Battlecard"
icon-name="utility:email" onclick={emailContent}></lightning-menu-item>
<lightning-menu-item value={battlecard.Client__c} label="View in Client"
icon-name="utility:open" onclick={navigateToWebPage}>
</lightning-menu-item>
<lightning-menu-item value={battlecard.Client__c} label="Edit in Client"
icon-name="utility:edit" onclick={navigateToWebPage}>
</lightning-menu-item>
<lightning-menu-item value={battlecard.Name} label="Open this Battlecard for All"
icon-name="utility:expand_all" onclick={expandThisBattlecardOnAll}>
</lightning-menu-item>
<lightning-menu-item value="CollapseAll" label="Collapse All"
icon-name="utility:collapse_all" onclick={collapseAll}>
</lightning-menu-item>
</lightning-button-menu>
<div class="slds-box slds-theme_shade">
<p key={battlecard.Id}>{battlecard.Title__c}</p>
<p key={battlecard.Id}>{battlecard.Subtitle__c}</p>
<p key={battlecard.Id}>{battlecard.Summary__c}</p>
<lightning-formatted-rich-text value={battlecard.Content__c}>
</lightning-formatted-rich-text>
</div>
</lightning-accordion-section>
</template>
</lightning-accordion>
</lightning-accordion-section>
</div>
</template>
</lightning-accordion>
</template>
<template if:true={error}>
<c-error-panel errors={error}></c-error-panel>
</template>
</div>
</template>
Here is the related JS controller...
import { LightningElement, api, track, wire } from 'lwc';
import getAccountCompetitors from '@salesforce/apex/AccountCompetitorController.getAccountCompetitors';
import { refreshApex } from '@salesforce/apex';
import { NavigationMixin } from 'lightning/navigation';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
export default class Battlecards extends NavigationMixin(LightningElement) {
@api recordId;
// used for testing in LDS
testRecordId = '0014T000002zOYaQAM';
defualtClientLink = 'https://google.com';
@track competitors;
@track error;
@track refreshes = 0;
allCompetitors = [];
/** Wired Apex result so it can be refreshed programmatically */
wiredCompetitorResult;
// wire the Apex method to the competitors property
// using testRecordId for testing purposes in LDS
@wire(getAccountCompetitors, { accountId: '$testRecordId' })
wiredCompetitors(result) {
this.wiredCompetitorResult = result;
if(result.data) {
this.competitors = result.data;
this.error = undefined;
// capture all the Competitor Sections for opening all at once
this.competitors.forEach(competitor => {
this.allCompetitors.push(competitor.Name);
});
}
else if (result.error){
this.error = result.error;
this.competitors = undefined;
}
}
refreshData() {
this.refreshes++;
return refreshApex(this.wiredCompetitorResult);
}
collapseAllCompetitors() {
var allCompetitors = this.template.querySelector('lightning-accordion');
allCompetitors.activeSectionName = "";
return null;
}
collapseAll() {
var all = this.template.querySelectorAll('lightning-accordion');
all.forEach(function(thisAccordian) {
thisAccordian.activeSectionName = "";
});
}
expandThisBattlecardOnAll2() {
var all = this.template.querySelectorAll('lightning-accordion');
all.forEach(function(thisAccordian) {
thisAccordian.activeSectionName = "";
});
}
expandThisBattlecardOnAll(event) {
var competitorList = this.allCompetitors;
var battlecardType = event.target.value;
var allAccordianElements = this.template.querySelectorAll('lightning-accordion');
var populateFirstAccordian = true; // this is a workaround that assume the main accordian will always be first
allAccordianElements.forEach(function(thisAccordian) {
if(populateFirstAccordian){
populateFirstAccordian = false;
thisAccordian.activeSectionName = competitorList;
//
}
else {
thisAccordian.activeSectionName = battlecardType;
}
});
}
emailContent(event) {
var clientIdentifier = event.target.value;
var emailType = event.target.label;
var messageString;
var emailAddress = 'someperson@client.com';
// TODO - call out to client email system
// need to define the value in the button to be something relevant to the client server
// need to get the current users email address
// build message
if(!emailType){
messageString = 'client data has been sent';
}
else if (emailType === 'Email this Competitor Card') {
messageString = `The client data for ${clientIdentifier} has been sent to ${emailAddress}`;
}
else if (emailType === 'Email this Battlecard') {
messageString = `The client data for this ${clientIdentifier} bBattlecard has been sent to ${emailAddress}`;
}
const toastEvent = new ShowToastEvent({
title: 'Email Sent',
message: messageString,
variant: 'success',
});
this.dispatchEvent(toastEvent);
}
navigateToWebPage(event) {
// get the incoming Url
var targetURL = event.target.value;
// check if there is a value to use
if(!targetURL){
targetURL = this.defualtClientLink;
}
// Navigate to a URL
this[NavigationMixin.Navigate]({
type: 'standard__webPage',
attributes: {
url: targetURL
}
},
false // true - Replaces the current page in your browser history with the Url
// but causes the originating page to navigate to App Builder ???
);
}
}
Any idea how I can access these elements, with Locker Service active?