2

I have a variable 'contactList' wired to an apex method which will return a list of contact. There is another imperative method will return a list of contact filtered by 'Name' field. The contact list rendered well after the page init, but after I change the value of 'contactList' by JS, the frontend page didn't display the record list retrieved from apex method. Firsr Load After click search button the list changed to below, but the contactList are not empty. After search Below is code snippet of the code.

    --------------------contactList.html----------------------
    <template>
        <lightning-card>
            <div style="display: inline-block" slot='actions'>
                <lightning-button label="Search" onclick={searchRecords}></lightning-button>
                <lightning-input data-id='searchInputId' style="display: inherit" placeholder='Search By Name' onchange={changeSearchValue} value={searchValue}></lightning-input>
                &nbsp;&nbsp;
                <lightning-button label="New" onclick={showForm}></lightning-button>
            </div>
            <template for:each={contactList.data} for:item='contact' for:index='itemindex'>
                <c-custom-contact-list-item key={contact.Id} contact={contact} if-check={checkAllVar} item-index={itemindex} onitemchecked={modifySelectedList}></c-custom-contact-list-item>
            </template>
        </lightning-card>
    </template>
    ------------------contactList.js----------------------
    import { LightningElement, wire, track } from 'lwc';
    import getContactList from '@salesforce/apex/ContactController.getContactList';
    import findContacts from '@salesforce/apex/ContactController.findContacts';
    import { ShowToastEvent } from 'lightning/platformShowToastEvent'

    export default class ContactList extends LightningElement {
        @wire(getContactList) contactList;
        searchValue = '';

        showForm(){
            let modalIten = this.template.querySelector('section.slds-modal');
            modalIten.classList.add('showModel');
        }

        changeSearchValue(event){
            //console.log(this.searchValue);
            this.searchValue = event.target.value;
        }

        searchRecords(){
            console.log(this.searchValue);
            findContacts({searchKey : this.searchValue}).then(result => {
                console.log(JSON.stringify(result));  // After called this method, the returned value will overwrite this.contactList;
                this.contactList = result;
            }).catch(error => {
                console.log(error);
            });
            this.template.querySelector('[data-id="searchInputId"]').value = null;
            this.searchValue = null;
        }
    }
    --------------------customContactListItem.html-------------------
    <template>
        <lightning-layout class='list-line'>
            <lightning-layout-item class='slds-truncate' style="width: 3.3333333333%" >
                <lightning-input type='checkbox' variant='label-hidden' class="listCheckbox" checked={changeCheck} onchange={handleCheck}></lightning-input>
            </lightning-layout-item>
            <lightning-layout-item class='slds-truncate slds-size_1-of-6 slds-text-align_center'>
                <a onclick={openDetail}>{contact.Name}</a>
            </lightning-layout-item>
            <lightning-layout-item class='slds-truncate slds-size_1-of-6 slds-text-align_center'>
                {contact.Phone}
            </lightning-layout-item>
            <lightning-layout-item class='slds-truncate slds-size_1-of-6 slds-text-align_center'>
                {contact.Email}
            </lightning-layout-item>
            <lightning-layout-item class='slds-truncate slds-size_1-of-6 slds-text-align_center'>
                {contact.Title}
            </lightning-layout-item>
            <lightning-layout-item class='slds-truncate slds-size_1-of-6 slds-text-align_center'>
                <img src={contact.Picture__c} width="25px" height="25px"></img>
            </lightning-layout-item>
        </lightning-layout>
    </template>
    ---------------------------------ContactController.cls------------------------------
    public with sharing class ContactController {

        @AuraEnabled(cacheable=true)
        public static List<Contact> getContactList() {
            return [SELECT Id, Name, Title, Phone, Email, Picture__c FROM Contact WHERE Picture__c != null LIMIT 10];
        }

        @AuraEnabled(cacheable=true)
        public static List<Contact> findContacts(String searchKey) {
            String key = '%' + searchKey + '%';
            List<Contact> list_con = [SELECT Id, Name, Title, Phone, Email, Picture__c FROM Contact WHERE Name LIKE :key AND Picture__c != null LIMIT 10];
            System.debug(searchKey);
            System.debug(list_con);
            return list_con;
        }
    }
1

From your console log:

So a wire response in JSON format looks something like

{ "data" : [Your response]}

Now, imperative method response looks like

[ {Your response} ,{Your response}]

In your searchRecords() method you are just populating just this.contactList

The markup template:for is expecting the data in data attribute. <template for:each={contactList.data}

In your searchRecords() method you are just populating just this.contactList, not the data attribute of this.contactList

searchRecords(){
        console.log(this.searchValue);
        findContacts({searchKey : this.searchValue}).then(result => {
            console.log(JSON.stringify(result));  // After called this method, the returned value will overwrite this.contactList;
            this.contactList = {};
            this.contactList.data = result;
        }).catch(error => {
            console.log(error);
        });
  • This answer perfectly solved my problem after I add '.data' behind this.contactList. Thanks. – Zas Aug 19 at 13:01
3

This is because, wired service always returns an object to property of function in the data structure {data:some_result,error:some_error}.

But imperative method promise will resolve to exactlky whatever you are returning from Apex method.

So, initially as you are referring to contactList.data, its loading but later when you are searching through findContacts, you are over-writing it with array in which there is no data.

IMPORTANT:

I would recommend to use below where you just need findContacts. Wired service will fetch the data again whenever there is change in dynamic property '$searchKey'.

import { LightningElement, wire, track } from 'lwc';
import findContacts from '@salesforce/apex/poc.findContacts';
import { ShowToastEvent } from 'lightning/platformShowToastEvent'

export default class ContactList extends LightningElement {
    searchKey = '';
    @wire(findContacts, { searchKey: '$searchKey' }) contactList;

    showForm() {
        let modalIten = this.template.querySelector('section.slds-modal');
        modalIten.classList.add('showModel');
    }

    changeSearchValue(event) {
        //console.log(this.searchValue);
        this.searchValue = event.target.value;
    }

    searchRecords() {
        console.log(this.searchValue);
        this.searchKey = this.template.querySelector('[data-id="searchInputId"]').value;
        this.template.querySelector('[data-id="searchInputId"]').value = null;
        this.searchValue = null;
    }
}

There is no need getContactList. Also whenever searchKey changes, wire will re-fetch the results.

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.