[SalesForce] How to change wired data list after get data from imperative apex method

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;
        }
    }

Best Answer

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);
        });
Related Topic