function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Lwc SeekarLwc Seekar 

LWC Form Custom Save (Need some fix) simple one

I would like to save the data filled in the form as shown in below. How ever i am not understanding how to do. 

I have a quick action on Account object , on click of quick action button customer opens the form  as shown below . 


User-added image
Here account name gets autopopulated and additional note needs to be filled by user and on hit on save button this needs to get saved in "Customer object" 

1.Account name : its a custom dynamic lookup
where we can search the record . 

code :

<template>
    <lightning-card>
      <header class="slds-modal__header" data-aura-rendered-by="142:2755;a">
        <h2 class="slds-modal__title" data-aura-rendered-by="143:2755;a"><b>Customer</b></h2>
        </header>
        <div class="slds-m-around--xx-large ">
  
    <div class="form-group">
         <c-custom-Lookup-Lwc icon-name="standard:account"
            s-object-api-name="Account"
            label="Account Name "
            onlookupupdate={lookupRecord}
            placeholder="Account here..."></c-custom-Lookup-Lwc>
    </div>  


    <div class="form-group">  
              <lightning-textarea
              max-length="100"
              message-when-value-missing="Please enter the description"
              label="Additional Note"
              required
              value={description}
              onchange={handleChange}
              class="textAreaCSS"></lightning-textarea>
            </div> 

        
      <footer class="slds-modal__footer" data-aura-rendered-by="145:2889;a">
        <div>
          <lightning-button variant="neutral" label="Cancel" onclick={closeAction} ></lightning-button>
          <lightning-button variant="brand" label="Save" onclick={saveAction} ></lightning-button>
        </div>
      </footer>
    
      </div>
    </lightning-card>
  </template>
  =========================================
  import { LightningElement,wire,api,track} from 'lwc';
import { CloseActionScreenEvent } from 'lightning/actions';
export default class CustomerQA extends LightningElement {
    @api records;
    @api error;
    
    lookupRecord(event){
      alert('Selected Record Value on Parent Component is ' +  JSON.stringify(event.detail.selectedRecord));
    }

    closeAction(){
        this.dispatchEvent(new CloseActionScreenEvent());
    }

   saveAction(event){
    }   
}

=======================================================
customlookuplwc.html

<template>
    <div class="slds-form-element" onmouseleave={toggleResult}  data-source="lookupContainer">      
        <div class="slds-combobox_container slds-has-selection">
          <label class="slds-form-element__label" for="combobox-id-1">{label}</label>
          <div class="lookupInputContainer slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click" aria-expanded="false" aria-haspopup="listbox" role="combobox"> 
           <div class="slds-combobox__form-element slds-input-has-icon slds-input-has-icon_left-right" role="none">
              <div class="searchBoxWrapper slds-show">
                <!--Lookup Input Field-->
                <lightning-input                   
                   type="search"
                   data-source="searchInputField"
                   onclick={toggleResult}
                   onchange={handleKeyChange}
                   is-loading={isSearchLoading}
                   value={searchKey}
                   variant="label-hidden"
                   placeholder={placeholder}
               ></lightning-input>  
              </div>
              
            <!--Lookup Selected record pill container start-->  
            <div class="pillDiv slds-hide">        
              <span class="slds-icon_container slds-combobox__input-entity-icon">
                <lightning-icon icon-name={iconName} size="x-small" alternative-text="icon"></lightning-icon>  
              </span>
              <input type="text"
                     id="combobox-id-1"
                     value={selectedRecord.Name}       
                     class="slds-input slds-combobox__input slds-combobox__input-value"
                     readonly
                     />
              <button class="slds-button slds-button_icon slds-input__icon slds-input__icon_right" title="Remove selected option">
              <lightning-icon icon-name="utility:close" size="x-small" alternative-text="close icon" onclick={handleRemove}></lightning-icon> 
             </button>
            </div>  
            </div>
        
            <!-- lookup search result part start-->
            <div style="margin-top:0px" id="listbox-id-5" class="slds-dropdown slds-dropdown_length-with-icon-7 slds-dropdown_fluid" role="listbox">
              <ul class="slds-listbox slds-listbox_vertical" role="presentation">
                <template for:each={lstResult} for:item="obj">
                <li key={obj.Id} role="presentation" class="slds-listbox__item">
                  <div data-recid={obj.Id} onclick={handelSelectedRecord} class="slds-media slds-listbox__option slds-listbox__option_entity slds-listbox__option_has-meta" role="option">
                    <span style="pointer-events: none;" class="slds-media__figure slds-listbox__option-icon" >
                      <span class="slds-icon_container" >
                          <lightning-icon icon-name={iconName} size="small" alternative-text="icon" ></lightning-icon>  
                      </span>
                    </span>
                    <span style="pointer-events: none;" class="slds-media__body" >
                      <span  class="slds-listbox__option-text slds-listbox__option-text_entity">{obj.Name}</span>
                    </span>
                  </div>
                </li>
                </template>
                <!--ERROR msg, if there is no records..-->
                <template if:false={hasRecords}>
                  <li class="slds-listbox__item" style="text-align: center; font-weight: bold;">No Records Found....</li>
                </template>
              </ul>
             
            </div>
          </div>
        </div>
      </div>
  </template>
  =============================================
  customlookuplwc.js:  
  import { LightningElement, api, wire } from 'lwc';
// import apex method from salesforce module 
import fetchLookupData from '@salesforce/apex/CustomLookupLwcController.fetchLookupData';
import fetchDefaultRecord from '@salesforce/apex/CustomLookupLwcController.fetchDefaultRecord';
import { CurrentPageReference } from 'lightning/navigation';
const DELAY = 300; // dealy apex callout timing in miliseconds  

// Start
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import NAME_FIELD from '@salesforce/schema/Account.Name';
// end 

export default class CustomLookupLwc extends LightningElement {
    // public properties with initial default values 
    @api label = 'custom lookup label';
    @api placeholder = 'search...Acc...';
    @api iconName = 'standard:account';
    @api sObjectApiName = 'Account';
    @api defaultRecordId = '';
    @api recordId;

    // private properties 
    lstResult = []; // to store list of returned records   
    hasRecords = true;
    searchKey = ''; // to store input field value 
    isSearchLoading = false; // to control loading spinner  
    delayTimeout;
    selectedRecord = {}; // to store selected lookup record in object formate 

   //getting record id from below function 
    @wire(CurrentPageReference)
    getStateParameters(currentPageReference) {
        if (currentPageReference) {
            this.recordId = currentPageReference.state.recordId;
            console.log('this.recordId==35===' + this.recordId);
          }
    }

// initial function to populate default selected lookup record if defaultRecordId provided  
    connectedCallback() {
        try{
            if (this.recordId != '') {
                fetchDefaultRecord({ recordId: this.recordId, 'sObjectApiName': this.sObjectApiName })
                    .then((result) => {
                        console.log('result===== ',result);
                        if (result != null) {
                            this.searchKey = result.Name;
                            console.log('this.searchKey===== ',this.searchKey);
                            this.selectedRecord = result;
                            this.handelSelectRecordHelper(); // helper function to show/hide lookup result container on UI
        
    //creating a custom event to pass the Account name to parent                
        const answerEvent = new CustomEvent("accname", { detail: this.searchKey });
        this.dispatchEvent(answerEvent);         
                       
                        }
                    })
                    .catch((error) => {
                        this.error = error;
                        this.selectedRecord = {};
                        console.error('OUTPUT: ', error);

                    });
            }
        } catch (error) {
            console.error('OUTPUT: ', error);
        }
    }

// wire function property to fetch search record based on user input
    @wire(fetchLookupData, { searchKey: '$searchKey', sObjectApiName: '$sObjectApiName' })
    searchResult(value) {
        const { data, error } = value; // destructure the provisioned value
        this.isSearchLoading = false;
        if (data) {
            this.hasRecords = data.length == 0 ? false : true;
            this.lstResult = JSON.parse(JSON.stringify(data));
        }
        else if (error) {
            console.log('(error---> ' + JSON.stringify(error));
        }
    };

// update searchKey property on input field change  
    handleKeyChange(event) {
        // Debouncing this method: Do not update the reactive property as long as this function is
        // being called within a delay of DELAY. This is to avoid a very large number of Apex method calls.
        this.isSearchLoading = true;
        window.clearTimeout(this.delayTimeout);
        const searchKey = event.target.value;
        this.delayTimeout = setTimeout(() => {
            this.searchKey = searchKey;
        }, DELAY);
    }

// method to toggle lookup result section on UI 
    toggleResult(event) {
        const lookupInputContainer = this.template.querySelector('.lookupInputContainer');
        const clsList = lookupInputContainer.classList;
        const whichEvent = event.target.getAttribute('data-source');
        switch (whichEvent) {
            case 'searchInputField':
                clsList.add('slds-is-open');
                break;
            case 'lookupContainer':
                clsList.remove('slds-is-open');
                break;
        }
    }

    // method to clear selected lookup record  
    handleRemove() {
        console.log('handleRemove');
        this.searchKey = '';
        this.selectedRecord = {};
        this.lookupUpdatehandler(undefined); // update value on parent component as well from helper function 

        // remove selected pill and display input field again 
        const searchBoxWrapper = this.template.querySelector('.searchBoxWrapper');
        searchBoxWrapper.classList.remove('slds-hide');
        searchBoxWrapper.classList.add('slds-show');

        const pillDiv = this.template.querySelector('.pillDiv');
        pillDiv.classList.remove('slds-show');
        pillDiv.classList.add('slds-hide');
    }

    // method to update selected record from search result 
    handelSelectedRecord(event) {
        var objId = event.target.getAttribute('data-recid'); // get selected record Id 
        this.selectedRecord = this.lstResult.find(data => data.Id === objId); // find selected record from list 
        this.lookupUpdatehandler(this.selectedRecord); // update value on parent component as well from helper function 
        this.handelSelectRecordHelper(); // helper function to show/hide lookup result container on UI
    }

    /*COMMON HELPER METHOD STARTED*/

    handelSelectRecordHelper() {
        this.template.querySelector('.lookupInputContainer').classList.remove('slds-is-open');
        const searchBoxWrapper = this.template.querySelector('.searchBoxWrapper');
        searchBoxWrapper.classList.remove('slds-show');
        searchBoxWrapper.classList.add('slds-hide');
        const pillDiv = this.template.querySelector('.pillDiv');
        pillDiv.classList.remove('slds-hide');
        pillDiv.classList.add('slds-show');
    }

    // send selected lookup record to parent component using custom event
    lookupUpdatehandler(value) {
        const oEvent = new CustomEvent('lookupupdate',
            {
                'detail': { selectedRecord: value }
            }
        );
        this.dispatchEvent(oEvent);
    }
}
============
public class CustomLookupLwcController {
    // Method to fetch lookup search result   
     @AuraEnabled(cacheable=true)
     public static list<sObject> fetchLookupData(string searchKey , string sObjectApiName) {    
         List < sObject > returnList = new List < sObject > ();
 
         string sWildCardText = '%' + searchKey + '%';
         string sQuery = 'Select Id,Name From ' + sObjectApiName + ' Where Name Like : sWildCardText order by createdDate DESC LIMIT 5';
         for (sObject obj: database.query(sQuery)) {
             returnList.add(obj);
         }
         return returnList;
     }
     
     // Method to fetch lookup default value 
     @AuraEnabled
     public static sObject fetchDefaultRecord(string recordId , string sObjectApiName) {
         string sRecId = recordId;    
         string sQuery = 'Select Id,Name From ' + sObjectApiName +' Where Id =\''+ sRecId+'\'  LIMIT 1' ;
         for (sObject obj: database.query(sQuery)) {
             return obj;
         }
         return null;
     }
     
 }
AshwiniAshwini (Salesforce Developers) 
Hi @Lwc Seekar,
 In orderTo save the data filled in the form to a "Customer" object, you  can implement the saveAction method in your LWC. You can refer below high-level steps:
  •  Create an Apex method which inserts a new "Customer" record with the data you want to save. This Apex method should accept the Account Name and Additional Note as parameters.
public with sharing class CustomerQAController {
    @AuraEnabled
    public static void createCustomerRecord(String accountName, String additionalNote) {
        Customer__c newCustomer = new Customer__c();
        newCustomer.Account_Name__c = accountName;
        newCustomer.Additional_Note__c = additionalNote;

        // Insert the new "Customer" record
        insert newCustomer;
    }
}
  • In your LWC JavaScript, call the Apex method when the user clicks the "Save" button. You can pass the selected account name (this.selectedAccountName) and the additional note (this.description) as parameters to the Apex method.
import { LightningElement, api } from 'lwc';
import { createCustomerRecord } from '@salesforce/apex/CustomerQAController.createCustomerRecord';

export default class CustomerQA extends LightningElement {
    @api records;
    @api error;
    selectedAccountName;
    description;

    // ... (existing code)

    saveAction() {
        createCustomerRecord({ accountName: this.selectedAccountName, additionalNote: this.description })
            .then(result => {
                // Handle the result, e.g., show a success message
            })
            .catch(error => {
                // Handle any errors, e.g., show an error message
            });
    }
}
  •  You can handle the success and errors in the then and catch blocks of the Promise returned by the Apex method call.  
Related: https://www.salesforcelwc.in/2019/04/how-to-create-record-in-lightning-web.html
https://www.forcetalks.com/blog/create-and-insert-record-in-lwc-without-using-record-edit-form-salesforce-developer-guide/ 

​​​​​​​Thanks.