I have two event handlers, one is fired when the user types a keystroke that I capture with the onkeyup event and the other is fired when they check or uncheck a checkbox which I capture with a onchange event.
This is in the context of a Salesforce Lightning Web Component.
I want the list of accounts to be refreshed when either event fires, so I took the code out of the event handler and put it into a method and called the method from both handlers, but it won't work outside the event handlers. I access nothing from the event handlers in the method. First I set local variables and then I call the method.
Can anyone tell me why this doesn't work?
Here is the "html" for the Lightning Web Component
accountTypeAheadSearch.html:
<template>
<article class="slds-card slds-var-p-around_small">
<h1>Account Type-Ahead Search Demo LWC</h1>
<div>
<lightning-input label="Search for account" id="searchFor" onkeyup={handleKeyUp} value={searchString}></lightning-input>
<lightning-checkbox-group label="Show contacts" id="showContactsCheckbox" onchange={handleShowContactChange}
options={contactsOptions} value={showContactsValue}
>
</lightning-checkbox-group>
</div>
<template if:true={showResults}>
<h2>Search Results:</h2>
<template for:each={searchResults} for:item="searchResult">
<c-account-type-ahead-search-link indentlevel='0' key={searchResult.key} link={searchResult.link} name={searchResult.name}>
</c-account-type-ahead-search-link>
<template for:each={searchResult.contacts} for:item="searchContact">
<c-account-type-ahead-search-link indentlevel='1' key={searchContact.key} link={searchContact.link} name={searchContact.name}>
</c-account-type-ahead-search-link>
</template>
</template>
<template if:false={searchResults.length}>
<h2>No matching accounts</h2>
</template>
</template>
</article>
</template>
Here is the JavaScript controller: accountTypeAheadSearch.js:
import { LightningElement, api } from 'lwc';
import getMatchingAccounts from '@salesforce/apex/AccountTypeAheadSearchHelper.getMatchingAccounts';
export default class AccountTypeAheadSearch extends LightningElement {
searchString = '';
@api searchResults = [];
@api showResults = false;
showContacts = false;
showContactsValue = ['showContactsYes'];
connectedCallback() {
console.log('connectedCallback BEGIN');
this.showResults = false;
this.showContacts = true;
console.log('connectedCallback END');
}
get contactsOptions() {
return [
{ label: 'Show Contacts', value: 'showContactsYes' }
];
}
handleShowContactChange(event) {
const val = event.target.value;
if (val == 'showContactsYes') {
this.showContacts = true;
} else {
this.showContacts = false;
}
getMatchingAccounts({ searchString: this.searchString, showContacts: this.showContacts })
.then(result => {
this.showResults = true;
this.searchResults = result;
})
.catch(error => {
this.showResults = false;
console.log('Error in handleKeyUp');
console.log(error);
});
}
refreshSearchResults() {
getMatchingAccounts({ searchString: this.searchString, showContacts: this.showContacts })
.then(result => {
this.showResults = true;
this.searchResults = result;
})
.catch(error => {
this.showResults = false;
console.log('Error in handleKeyUp');
console.log(error);
});
}
handleKeyUp(event) {
const val = event.target.value;
this.searchString = val;
if (this.searchString) {
getMatchingAccounts({ searchString: this.searchString, showContacts: this.showContacts })
.then(result => {
this.showResults = true;
this.searchResults = result;
})
.catch(error => {
this.showResults = false;
console.log('Error in handleKeyUp');
console.log(error);
});
} else {
this.showResults = false;
}
}
}
As you can see, I have copied the same code in the two event handlers in a method called refreshSearchResults, but when I try this, it doesn't work.
handleShowContactChange(event) {
const val = event.target.value;
if (val == 'showContactsYes') {
this.showContacts = true;
refreshSearchResults();
} else {
this.showContacts = false;
}
}
handleKeyUp(event) {
const val = event.target.value;
this.searchString = val;
if (this.searchString) {
refreshSearchResults();
} else {
this.showResults = false;
}
}
The handleKeyUp method does nothing and produces no error and the handleShowContactChange method gives an error I cannot understand:
[NoErrorObjectAvailable] Script error. a()@https://static.lightning.force.com/na213/auraFW/javascript/QPQi8lbYE8YujG6og6Dqgw/aura_prod.js:992:196 {anonymous}()@https://static.lightning.force.com/na213/auraFW/javascript/QPQi8lbYE8YujG6og6Dqgw/aura_prod.js:992:389 Le()@https://static.lightning.force.com/na213/auraFW/javascript/QPQi8lbYE8YujG6og6Dqgw/aura_prod.js:13:42189 y.dispatchEvent()@https://static.lightning.force.com/na213/auraFW/javascript/QPQi8lbYE8YujG6og6Dqgw/aura_prod.js:13:13675 y.handleChange()@https://creative-shark-5y8u3x-dev-ed.lightning.force.com/components/lightning/checkboxGroup.js:1:4152
I think the Apex code is not relevant, but here it is, just in case:
public with sharing class AccountTypeAheadSearchHelper {
/**
* Given a searchString, returns an array of MatchingAccountsWrappers for the LWC to consume
*
* @param searchString a part of the name of the account to search for
*
* @return an array of MatchingAccountsWrappers
*/
@AuraEnabled
public static MatchingAccountsWrapper[] getMatchingAccounts(String searchString, Boolean showContacts) {
String searchSpec = '%' + searchString + '%';
List<Account> accountsFound;
if (showContacts) {
accountsFound = [
SELECT Id, Name,
(SELECT Id, Name FROM Contacts ORDER BY Name)
FROM Account
WHERE Name LIKE :searchSpec
ORDER BY Name];
} else {
accountsFound = [
SELECT Id, Name
FROM Account
WHERE Name LIKE :searchSpec
ORDER BY Name];
}
List<MatchingAccountsWrapper> matchingAccounts = new List<MatchingAccountsWrapper>();
for (Account ma : accountsFound) {
MatchingAccountsWrapper mar = new MatchingAccountsWrapper(ma.Id, ma.Name, showContacts ? ma.Contacts: null);
matchingAccounts.add(mar);
system.debug('#@# matching account.name = ' + ma.Name);
}
return matchingAccounts;
}
private class MatchingAccountsWrapper {
public MatchingAccountsWrapper(String k, String n) {
key = k;
name = n;
}
public MatchingAccountsWrapper(String k, String n, List<Contact> c) {
key = k;
name = n;
relatedContacts = c;
}
public MatchingAccountsWrapper(Account a) {
key = a.Id;
name = a.Name;
}
@AuraEnabled
public string key {get; set;}
@AuraEnabled
public string name {get; set;}
@AuraEnabled
public string link {get {
return URL.getSalesforceBaseUrl().toExternalForm() + '/' + this.key;
} set;}
private List<Contact> relatedContacts {get; set;}
@AuraEnabled
public List<MatchingContactsWrapper> contacts {get {
if (relatedContacts != null) {
List<MatchingContactsWrapper> matchingContacts = new List<MatchingContactsWrapper>();
for (Contact matchingContact : relatedContacts) {
MatchingContactsWrapper mac = new MatchingContactsWrapper(matchingContact);
matchingContacts.add(mac);
}
return matchingContacts;
} else {
return null;
}
} set;}
}
private class MatchingContactsWrapper {
public MatchingContactsWrapper(Contact c) {
key = c.Id;
name = c.Name;
}
@AuraEnabled
public string key {get; set;}
@AuraEnabled
public string name {get; set;}
@AuraEnabled
public string link {get {
return URL.getSalesforceBaseUrl().toExternalForm() + '/' + this.key;
} set;}
}
}