Sunday, May 15, 2022

Add Delete rows dynamically in Lightning Data Table in LWC Salesforce

Hello Guys, in this post we'll learn how to add delete rows dynamically in Lightning Data table in Lightning Web Components(LWC) in Salesforce with the proper Example.

Apex Class

public class AddDeleteRowLWCController {

    @AuraEnabled
    public static List getAccounts(){
        return [SELECT Id, Name, AccountNumber, Site FROM Account LIMIT 5];
    }
    @AuraEnabled
    public static Account addAccount(String account){
        Account accObj = (Account) System.JSON.deserialize(account, Account.class);
        insert accObj;
        return accObj;
    }
}
addDeleteRowLWC.html

<template>
    <lightning-card title="">
        <lightning-button variant="brand" label="Add Account" onclick={openAddAccountModal} ></lightning-button>
        <div class="slds-grid slds-no-flex slds-var-p-around_medium	">
            <div class="slds-col slds-size_12-of-12">
                <lightning-datatable key-field="Id"
                                    data={accountData}
                                    columns={columns}
                                    onrowaction={handleRowAction}
                                    hide-checkbox-column
                                    >
                </lightning-datatable>                            
            </div>
        </div>
    </lightning-card>

    <template if:true={isModalOpen}>
        <!-- Modal/Popup Box LWC starts here -->
        <section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
            <div class="slds-modal__container">
                <!-- Modal/Popup Box LWC header here -->
                <header class="slds-modal__header">
                    <button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse" title="Close" onclick={closeModal}>
                        <lightning-icon icon-name="utility:close"
                            alternative-text="close"
                            variant="inverse"
                            size="small" ></lightning-icon>
                        <span class="slds-assistive-text">Close</span>
                    </button>
                    <h2 id="modal-heading-01" class="slds-text-heading_medium slds-hyphenate">Add Account</h2>
                </header>
                <!-- Modal/Popup Box LWC body starts here -->
                <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                    <lightning-input name="accountName" type="text"  label="Name" value={accountName} onchange={handleChange}></lightning-input>                    
                    <lightning-input name="accountNumber" type="Integer" label="AccountNumber" value={accountNumber} onchange={handleChange}></lightning-input>                    
                    <lightning-input name="accountSite" type="text" label="Site" value={accountSite} onchange={handleChange}></lightning-input>                    

                </div>
                <!-- Modal/Popup Box LWC footer starts here -->
                <footer class="slds-modal__footer">
                    <button class="slds-button slds-button_neutral" onclick={closeModal} title="Cancel">Cancel</button>
                    <button class="slds-button slds-button_brand" onclick={addAccount} title="Add Account">Add Account</button>
                </footer>
            </div>
        </section>
        <div class="slds-backdrop slds-backdrop_open"></div>
    </template>

</template>
addDeleteRowLWC.js

import { LightningElement } from 'lwc';
import getAccounts from '@salesforce/apex/AddDeleteRowLWCController.getAccounts';
import addAccount from '@salesforce/apex/AddDeleteRowLWCController.addAccount';

export default class AddDeleteRowLWC extends LightningElement {
    columns = [
        {label: 'Name', fieldName: 'Name', type: 'text', sortable: true},
        {label: 'Account Number', fieldName: 'AccountNumber', type: 'text', sortable: false},
        {label: 'Site', fieldName: 'Site', type: 'text', sortable: true},
        {type: "button-icon", typeAttributes: {iconName: "utility:delete", name: "delete", iconClass: "slds-icon-text-error"},fixedWidth: 50}     
    ];

    accountData = [];
    isModalOpen = false;
    accountName= '';
    accountNumber = '';
    accountSite = '';

    connectedCallback(){
        this.getAccounts();
    }
    getAccounts(){
        getAccounts()
        .then(result =>{
            this.accountData = result;
        })
        .catch(error =>{

        })
    }

    handleRowAction(event) {
		if (event.detail.action.name === "delete") {
			this.deleteSelectedRow(event.detail.row);
		}
	}
    deleteSelectedRow(deleteRow) {
		let newData = JSON.parse(JSON.stringify(this.accountData));
		newData = newData.filter((row) => row.Id !== deleteRow.Id);
        this.accountData = newData;		
	}
    openAddAccountModal(){
        this.isModalOpen = true;
    }
    closeModal() {        
        this.isModalOpen = false;
    }
    handleChange(event){
        if(event.target.name == 'accountName'){
            this.accountName = event.target.value;
        }else if(event.target.name == 'accountNumber'){
            this.accountNumber = event.target.value;
        }else if(event.target.name == 'accountSite'){
            this.accountSite = event.target.value;
        }
    }
    addAccount(){
        let accountToInsert = {
            Name : this.accountName,
            AccountNumber: this.accountNumber,
            Site : this.accountSite
        }
        addAccount({
            account: JSON.stringify(accountToInsert)
        })
        .then(result =>{            
            this.addAccountToList(result)
        })
        .catch(error =>{
            this.error = error;
        })        
    }
    addAccountToList(account){
        let localList;            
        if(this.accountData.length > 0){                        
            localList =JSON.parse(JSON.stringify(this.accountData));                
        }else{
            localList = [];                
        }
         
        localList.push({
            Id: account.Id,
            Name : account.Name,
            AccountNumber : account.AccountNumber,
            Site : account.Site,            
        })                                        
        this.accountData = localList;
        this.isModalOpen = false;    
    }
}
addDeleteRowLWC.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>54.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>
Output

If you guys have any question, please comment below, I'll be happy to answer your question.
#LWC, #LightningDataTable, #adddeleterowinlwc #salesforce #salesforcelightning

Related Posts
Lightning Data Table to Show Parent object data along with Count of the child in LWC Salesforce

Friday, May 13, 2022

Subscript is invalid because list is empty | Error in VF Page | Salesforce

Subscript is invalid because list is empty this error is comes on VF page if we are trying to access the list element on VF Page and in the apex the list has no rows.

Below is the example 

Here is my Apex Class

public Class myClass {

    public Account account {get;set;} 

public myClass(){

        recordId = System.currentPageReference().getParameters().get('recordId');

        this.account = [SELECT Id, Name,(select id,LastName FROM Contacts) FROM Account WHERE Id =:recordId];                

    }

}


VF Page

<apex:page renderAs="pdf" applyBodyTag="false" controller="myClass" >

<div class="header">

        <table>         

            <tr>

                <td style="background: #D6EEEE"><b>Account Name</b></td>   

                <td>{!account.Name}</td> 

                <td style="background: #D6EEEE"><b>Contact Last Name</b></td>  

                <td>{!account.Contacts[0].LastName}</td> 

        </tr>

    </table>



In order to solve this error we'll have to modify our code as below

public Class myClass {

    public Account account {get;set;} 

    public String contactLastName {get;set;}

public myClass(){

        recordId = System.currentPageReference().getParameters().get('recordId');

        contactLastName = '';

        this.account = [SELECT Id, Name,(select id,LastName FROM Contacts) FROM Account WHERE Id =:recordId];           

    if(this.account.contacts.size() >0){

        contactLastName = this.account.contacts[0].LastName;

    }     

    }

}


VF Page

<apex:page renderAs="pdf" applyBodyTag="false" controller="myClass" >

<div class="header">

        <table>         

            <tr>

                <td style="background: #D6EEEE"><b>Account Name</b></td>   

                <td>{!account.Name}</td> 

                <td style="background: #D6EEEE"><b>Contact Last Name</b></td>  

                <td><!--{!account.Contacts[0].Name}-->{!contactLastName}</td> 

        </tr>

    </table>


Hope this will solve your problem, Please comment below if you have any question. I'll be happy to help.

Sunday, April 3, 2022

How to Update custom metadata type record using Metadata API

 In this example, I'll show you how can we write an Apex class to update the custom metadata record using Metadata API

Please follow the below steps:

Step 1 : Create a Custom metadata object and a field, in our example our custom metadata object is StatesCitiesPincode__mdt and a custom field State__c

Step 2: Create a record by clicking on the Manage StatesCitiesPincode button at the top and then click on the new button

Step 3: Now we'll create an apex class which will be used to update the record, whenever we update the custom metadata record using metadata API the system does an actual deployment and we can track it by checking deployment Status through the Setup.


  public class CreateUpdateMetadataUtils implements Metadata.DeployCallback {
    // Method to track deploy results
    public void handleResult(Metadata.DeployResult result,
                             Metadata.DeployCallbackContext context) {
        if (result.status == Metadata.DeployStatus.Succeeded) {
            System.debug('success: '+ result);
        } else {
            System.debug('fail: '+ result);
        }
    }
}
  

  public with sharing class UpdateCustomMetadata {
    
    public static void updateRecord() {
        
        try {                
            Metadata.DeployContainer mdContainer = new Metadata.DeployContainer();
            
            Metadata.CustomMetadata customMetadata = new Metadata.CustomMetadata();
            customMetadata.fullName = 'StatesCitiesPincode__mdt.Uttar_Pradesh';
            customMetadata.Label='Uttar Pradesh';
            
            Metadata.CustomMetadataValue customField = new Metadata.CustomMetadataValue();
            customField.field = 'State__c';
            customField.value = 'UP';
            
            
            customMetadata.values.add(customField);                
            mdContainer.addMetadata(customMetadata);            
            
              
            CreateUpdateMetadataUtils  callback = new CreateUpdateMetadataUtils();            
            Id jobId = Metadata.Operations.enqueueDeployment(mdContainer, callback);                        
            
            
        } catch (exception e) {
            
        }                
    }        
}
  

you can execute the method from the Anonymous Apex window UpdateCustomMetadata.updateRecord();

Saturday, September 5, 2020

Formula Field to Convert date value into the Month Name as Text like JAN, FEB, etc.

 Hello All, In this article we would learn how can we convert the date value into the Month Name,
for example, if you have one DateTime field like Createddate and your requirement is to display the Month Name instead of date like if we have DateTime value as 2018-01-17T11:18:31.000+05:30 so with our formula field we can display this date as JAN  similarly 2018-02-17T11:18:31.000+05:30 as FEB.

So in one line, the formula is below, you can use it accordingly however I will explain it by breaking into all functions which we have used in this.


CASE(MONTH(DATEVALUE(CreatedDate )),1,'JAN',2,'FEB',3,'MAR',4,'APR',5,'MAY',6,'JUN',7,'JUL',8,'AUG',9,'SEP',10,'OCT',11,'NOV',12,'DEC','')


Explanation of different functions used.

DATEVALUE(expression) -- DATEVALUE function accepts DateTime as argument (dateTime can be text also) and converts it into the DATE. 

ex. DATEVALUE(2018-02-17T11:18:31.000+05:30)  returns 2018-01-17

MONTH(date) -- MONTH functions accept DATE as an argument and returns the month,which is basically a number between 1 for (January) and 12 for (December)

ex. MONTH(2018-01-17) returns 1

CASE(expression, value1, result1, value2, result2,...,else_result) -- Checks an expression against a series of values.  If the expression compares equal to any value, the corresponding result is returned. If it is not equal to any of the values, the else-result is returned

ex CASE(MONTH(DATEVALUE(CreatedDate )),1,'JAN',2,'FEB',3,'MAR',4,'APR',5,'MAY',6,'JUN',7,'JUL',8,'AUG',9,'SEP',10,'OCT',11,'NOV',12,'DEC','')

here MONTH(DATEVALUE(CreateDate)) works like an expression and returns value as 1, 2 etc which inturn used as an argument in CASE function and CASE functions returns result accordingly.


I hope this explanation helps you. Thanks!!


Sunday, May 26, 2019

How to use custom metadata types in the lighting flow.

Hello guys, In this article, we will learn how can we use Flow builder, Process builder, and Custom metadata types to update records.

I have a scenario in which I have one custom metadata type named as STATESCITIESPINCODE which contains pin codes of corresponding cities with their states, now whenever a user creates the records he enters state name and city name so our process builder calls flow which having logic how to get pin code corresponding to state and city to enter by the user while creating the record and then our process builder update the record with the pin code.

so first let's create the custom metadata type which having the states, cities, and corresponding pin codes,

So go to Setup >> Enter custom metadata in the search box >> click on Custom Metadata Types under Develop
so I have custom metadata types with three custom fields City, State, and Pincode



now we'll create the flow
so go to setup >> Enter Flow >> Click on Flows under Process Automation

So in our flow, first of all, we'll create the variables for this click on Manage on the left and then click on New Resource then the popup will come in the search box enter variable and click on the variable


Repeat the steps for creating the three variables varCity, varState, varPincode, and varId of datatype Text.
Create another variable varUpdateCityRecord with datatype as Record and Object type is as City, which will be used to update the record



Create another variable varGetPincodeRecord with datatype as Record and Object type is as StatesCitiesPincode( which is our custom metadata object), this will be used to store the value of pin code.




Now we have created the variables now we'll search for the records in the custom metadata type. so for this click on the element on the left and drag the GetRecords under data, a popup will come, give a suitable label, in the object search your custom metadata type name, in the condition requirement select Conditions are met







Now Click on Assignment under the Logic and drag it to right again the popup will come, give some Label then set the variable values



next and final step is to update the Record variable, for this click on the Update Records and drag it to the right again popup will come, give the suitable name and then in the select variable select the varUpdateCityRecord variable which will update the Record with the pin code.





join all them together and the finally your flow will look like this


Save the flow as autolauchedflow, and don't forget to activate it.

Now create the process builder which will run when we try to save our city Object record and will call the flow to update the record with the corresponding pin code

Select City as an object, in the criteria, select No criteria—just execute the actions! 


and in the immediate actions  Select Flow as an action, give an action name and select your flow which you just created and provide values to the flow variables



Save your process builder and don't forget to activate it

Now everything is done try to create the City Record give postcode and state values and click on save and your record will be updated with the corresponding pin code.

That's it guys,


Monday, May 13, 2019

Prepopulate Lookup in Lightning record edit form when it override to New button in Service Console

In this article, we would learn how can we auto-populate with parent account when creating a new child record from the related list of parent.

In Salesforce when you create a master-detail relationship between two objects and whenever you create a child record from the parent related list, the parent record automatically auto populate lookup field of its parent when you try to create the child record.
But if you override the child object's New button with some custom lightning component and try to create a new child record in this case the parent record does not automatically auto-populate the lookup field of its parent.

So in this article, we would learn how to automatically auto-populate the lookup field of its parent.

For example, we have Account and Address object, Account is the parent and the Address is the child object, also I override Address component's New button with the custom lightning component in which I am using lighting record edit form to create the new record.

Here is the code for the lightning component

LightinigRecordEditForm.cmp

  <aura:component implements="lightning:actionOverride,force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction"  access="global" >
    
    
    <!-- Attributes --> 
    <aura:attribute name="parentRecordId" type="String" />   
    <aura:handler name="init" value="this" action="{!c.doInit}"/> 
    
    <lightning:card iconName="standard:account" title="New Address" class="">
        <div class="slds-p-left_large slds-p-right_medium"> 
            <lightning:recordEditForm
                                      onload="{!c.handleLoad}"
                                      recordId="{!v.recordId}"
                                      onsubmit="{!c.onSubmit}"
                                      onsuccess="{!c.onSuccess}"
                                      onerror="{!c.onError}"       
                                      objectApiName="Address__c">
                <lightning:messages />
                <h3 class="slds-section__title slds-theme--shade primaryPaletteBorder test-id__section-header-container" >
                    <span class="test-id__section-header-title section-header-title slds-p-horizontal--small slds-truncate" >Address Information</span>
                </h3>
                <div class="slds-grid">
                    <div class="slds-col slds-size_6-of-12 slds-p-around_small">                 
                        <lightning:inputField fieldName="Name" aura:id="addressName" />
                    </div>
                    <div class="slds-col slds-size_6-of-12 slds-p-around_small">
                        <lightning:inputField fieldName="Account__c" value="{!v.parentRecordId}"/>
                    </div>
                </div>
                
                
                <lightning:layout horizontalAlign="center" class="slds-m-top_large">
                    <lightning:button variant="neutral" label="Cancel" title="Cancel" type="text" onclick="{!c.onCancel}"/>
                    <lightning:button variant="brand" type="submit" name="save" label="Save" />
                </lightning:layout>
            </lightning:recordEditForm>     
        </div>
    </lightning:card>
</aura:component>
  
LightningRecordEditFormController.js

  ({
    doInit: function(component, event, helper){
     
        var parentId = helper.getParentId(component , event, 'inContextOfRef');
        var context = JSON.parse(window.atob(parentId));
        component.set("v.parentRecordId", context.attributes.recordId);
   
    },
    onSuccess : function(component, event, helper) {
        var toastEvent = $A.get("e.force:showToast");
        toastEvent.setParams({
            "title": "Success!",
            "message": "The record has been Saved successfully."
        });
        toastEvent.fire();
    },
    onSubmit : function(component, event, helper) {
    },
    onLoad : function(component, event, helper) {
        var toastEvent = $A.get("e.force:showToast");
        toastEvent.setParams({
            "title": "Loaded!",
            "message": "The record has been Loaded successfully ."
        });
        toastEvent.fire();
    },
    onError : function(component, event, helper) {
        var toastEvent = $A.get("e.force:showToast");
        toastEvent.setParams({
            "title": "Error!",
            "message": "Error."
        });
        toastEvent.fire();
    }
 
 
})
  
LightningRecordEditFormHelper.js
({
  getParentId: function(component, event, name) {
        name = name.replace(/[\[\]]/g, "\\$&");       
        var url = window.location.href;     
        var regex = new RegExp("[?&]" + name + "(=1\.([^&#]*)|&|#|$)");
        var results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, " "));
    }
})
  

Tuesday, February 5, 2019

How to query fields which are in the fieldset using SOQL in Salesforce.

Hi all,
Today I am going to explain to you that how can you query all fields from fieldset.
Suppose you have created one fieldset in Contact object and you have also added some fields in that fileldset like this.

How to create fieldset in Salesforce?
Steps

  1. Enter your object name in the setup and click on fieldset.
  2. Click on New and enter details like it's label, API name etc.
  3. Click on save and then you will be redirected to on page where you can drag and drop all the fields which you want that should be in the fieldset.
So you are done with your fieldset and also you have added some fields to fieldset as well.
Now let's move to the next step.
So now you have two things

  1. Object API Name : Contact
  2. FieldSet API Name: testingFieldsetName (It will be same what you provide while creating fieldset)
Here is the code that will be used to query all fields available in the fieldset.


  String objectApiName = 'Contact';
String fieldSetName = 'testingFieldsetName';
       
//Get the fields from FieldSet
Schema.SObjectType sObjectTypeObj = Schema.getGlobalDescribe().get(objectApiName);
Schema.DescribeSObjectResult describeSObjectResultObj = sObjectTypeObj.getDescribe();           
Schema.FieldSet fieldSetObject = describeSObjectResultObj.FieldSets.getMap().get(fieldSetName);
      
//Field to be queried - fetched from fieldset
List<String> fieldsToQueryList = new List<String>();
       
for( Schema.FieldSetMember eachFieldSetMember : fieldSetObject.getFields() ){
    fieldsToQueryList.add(String.valueOf(eachFieldSetMember.getFieldPath()));
}
       
String query = 'SELECT '+ String.join(fieldsToQueryList , ',') + ' FROM CONTACT';
List<Contact> contactsList =  Database.query(query);
  
Hope this post helps you.