1

I'm trying to create a type-ahead in LWC wherein I'm using imperative approach(this is what I want to use - not @wire) to make get matching record names from back-end. However, when I type anything in the search box I get the below error:

This page has an error. You might just need to refresh it. First, would you give us some details? (We're reporting this as error ID: -491200357)

Below is the code:

HTML:

<template>
    <lightning-card title="Type-Ahead Imperative">
        <lightning-input type="text" onchange={handleChange} value={sSearchKey}></lightning-input>
        <template if:true={bShowAcctNames}>
            <template for:each={lstAcctNames} for:item="sAcctName">
                <p key={sAcctName}>{sAcctName}</p>
            </template>
        </template>
    </lightning-card>
</template>

JS

import { LightningElement } from 'lwc';
import ACCT_NAMES from '@salesforce/apex/AccountData.getAccountNames'
export default class ImperativeTypeAhead extends LightningElement {
    sSearchKey = '';
    lstAcctNames = [];
    bShowAcctNames = false;
    handleChange(event){
        this.sSearchKey = event.target.value;
        ACCT_NAMES({sSearchKey : '$sSearchKey'})
        .then(result =>{
            result.forEach(sName => {
                this.lstAcctNames.push(sName);
            });
            this.bShowAcctNames = true;
        })
        .catch(error=>{
            // eslint-disable-next-line no-console
            console.log('Error Occured : ',error);
        })
    }
}

The back-end call isn't made at all - I verified from debug logs. What's the issue here?

5
  • 1
    This is a string '$sSearchKey' and will be sent to the server as such. Plus, no need to have a reactive var inside an event handler. Plus, you'd need to refer to it as this.sSearchKey – Caspar Harmer Apr 1 '20 at 21:08
  • Also, you need to debounce/rate limit your input + the handlechange event is a lwc ComponentEvent - and has a structure of event.detail.value I think. – Caspar Harmer Apr 1 '20 at 21:09
  • The backend call is not being made because of a null error - there is no event.target.value. – Caspar Harmer Apr 1 '20 at 21:10
  • Can we see your apex? – Sebastian Kessel Apr 1 '20 at 22:08
  • Also, '$sSearchKey' is actually an accepted syntax, at least with an @api variable, but I suspect it works just as well otherwise. I do agree there is no need to have a reactive property there, though – Sebastian Kessel Apr 1 '20 at 22:09
0

So you're using imperative method calls all wrong here. With imperative calls you cannot fetch the value like '$someField' you must instead use this.someField to get the value and pass in the value to your method. I rewrote this to be a little shorter using async/await when fetching your results see below:

HTML

<template>
    <lightning-card title="Type-Ahead Imperative">
        <lightning-input type="text" value={searchKey} onchange={handleChange}></lightning-input>
        <template if:true={bShowAcctNames}>
            <template for:each={lstAcctNames} for:item="sAcctName" >
                <p key={sAcctName}>{sAcctName}</p>
            </template>
        </template>
    </lightning-card>
</template>

JS

import { LightningElement, track } from 'lwc';
import ACCT_NAMES from '@salesforce/apex/AccountData.getAccountNames'

export default class TypeAhead extends LightningElement {
  @track lstAcctNames = [];
  @track bShowAcctNames;
  @track searchKey;

  async handleChange(event){

    const srchResult = await ACCT_NAMES({ searchKey : event.detail.value })
      .catch( error => {
        this.lstAcctNames = [];
        console.error( "Error getting search result: ", error );
      });

    if( srchResult ){
      this.lstAcctNames = [ ...srchResult.map( result => result.Name ) ];
    }

    this.bShowAcctNames = this.lstAcctNames.length > 0;
  }
}

Apex

    @AuraEnabled
    public static List<Account> getAccountNames( String searchKey ){
        String searchKeyLike = '%' + searchKey + '%';
        return [
            SELECT Id, Name
            FROM Account
            WHERE Name LIKE: searchKeyLike
        ];
    }

enter image description here

3
  • this.lstAcctNames = [ ...srchResult.map( result => result.Name ) ---- Why do we use three dots (...) here? – sfdcnoob Apr 3 '20 at 0:34
  • track is reactive, but it does not know when items are pushed to an array due to depth. using the spread operator (...) it takes all elements of the array and assigns them to the new array. its the best way to assign current values in an array, and by reassigning this way track can see that the value has changed due to it NOT losing it due to depth – Ronnie Apr 3 '20 at 0:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.