How to use refreshApex to refresh the list in LWC

In this post , we will see the how to refresh the list in lwc using refreshApex concept.

List of topics covered in this post as below.
  • Display the contacts related to selected Account with sortable column & row actions
  • Adding new button on top of the account to create new contact
  • if user creating the new contact using new button ,the contact list will update automatically.
  • if user deleting the any contact using row actions,the contact list will update automatically.
In this logic am using using apex class to create ,delete & return the existing contacts.

To refresh the list , have added the import statement refreshApex in lwc js . if user creating/deleting the contact the cache data becomes stale. so after the creation/deletion method just call the refreshApex to query the server for updated data and refresh the cache.

Apex class :

public with sharing class ContactUtilities{

    //Method to return the list of contatcs based on selected account
    @AuraEnabled(Cacheable = true)
    public static List<Contact> getContacts(Id sourceAccount){
        return [SELECT Id, Name, Account.Name, LastName, FirstName, Email, Phone, MobilePhone
         From Contact where AccountId = :sourceAccount];

    //Method to delete the selected contacts
    public static void deleteContacts(list<Id> deleteContactIds){
        list<Contact> listContactToDelete = new list<Contact>();
        for (Id idContact : deleteContactIds){
            listContactToDelete.add(new Contact(Id = idContact));
        if (!listContactToDelete.isEmpty()){
            delete listContactToDelete;

    //Method to create contact
    public static void addContact(string firstName, string lastName, String email,id acntId){
        Contact con = new Contact();
        con.FirstName = firstName;
        con.LastName = lastName;
        con.Email = email;
con.AccountId = acntId;
            insert con;
        } catch (Exception ex){
            throw new AuraHandledException(ex.getMessage());

Lightning Web Component


<lightning-card class="slds-card slds-card_boundary related_list_card_border_top" title="ContactListView">

<!-- New button -->
<div slot="actions">
<lightning-button variant="neutral" label="New" type="text" onclick={createNewRecord}

<!--- Contact Table-->
<div style="width: auto;">
<template if:true={emptyList}>
<lightning-datatable data={data} columns={columns} key-field="id" show-row-number-column
hide-checkbox-column="true" onrowaction={handleRowActions} sorted-by={sortBy}
sorted-direction={sortDirection} onsort={handleSortdata}></lightning-datatable>
<template if:false={emptyList}>
There is no contacts
</div> <br />

<!-- Spinner -->
<div if:true={showLoadingSpinner}>
<lightning-spinner alternative-text="Loading" size="large"></lightning-spinner>

<!-- Detail view modal -->
<template if:true={ShowModal}>
<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 header -->
<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"
<h2 id="modal-heading-02" class="slds-text-heading_medium slds-hyphenate modalHeading"
if:true={editRecord}> Update Contact</h2>
<h2 id="modal-heading-0" class="slds-text-heading_medium slds-hyphenate modalHeading"
if:true={newRecord}>New Contact</h2>

<!-- showing record edit form -->
<div if:true={isEditForm} class="slds-theme_default">
<lightning-record-edit-form layout-type="Full" object-api-name="Contact" record-id={currentRecordId}>
<div if:true={error}>
<div class="slds-col slds-size_1-of-1">
<lightning-input-field field-name="FirstName" onchange={firstNameChange}>
<div class="slds-col slds-size_1-of-1">
<lightning-input-field field-name="LastName" onchange={lastNameChange}>
<div class="slds-col slds-size_1-of-1">
<lightning-input-field field-name="Email" onchange={emailChange}>

<br />
<ul class="slds-button-group-row slds-grid slds-grid_align-center">
<li class="slds-button-group-item">
<lightning-button class="slds-m-top_small" variant="brand" name="update"
label="save" onclick={handleSubmit}></lightning-button>
<li class="slds-button-group-item">
<lightning-button class="slds-m-top_small" variant="brand" type="text"
label="Cancel" onclick={closeModal}></lightning-button>

<div class="slds-backdrop slds-backdrop_open"></div>


import { LightningElement, track, wire, api } from 'lwc';
//Import Apex methods
import getContatcs from '@salesforce/apex/ContactUtilities.getContacts';
import deletecontact from '@salesforce/apex/ContactUtilities.deleteContacts';
import createContact from '@salesforce/apex/ContactUtilities.addContact';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { refreshApex } from '@salesforce/apex';
import { NavigationMixin } from 'lightning/navigation';

// row actions
const actions = [
{ label: 'Delete', name: 'delete' }

// datatable columns with row actions
const columns = [
{ label: 'First Name', fieldName: 'FirstName', type: "string", sortable: true },
{ label: 'Last Name', fieldName: 'LastName', type: "string", sortable: true },
{ label: 'Email', fieldName: 'Email', type: "email", sortable: true },
type: 'action',
typeAttributes: {
rowActions: actions,
menuAlignment: 'right'

export default class ConatctListViewWithRefreshApex extends NavigationMixin(LightningElement) {

// reactive variable
@api recordId;
@track data;
@track columns = columns;
@track record = [];
@track ShowModal = false;
@track currentRecordId;
@track isEditForm = false;
@track showLoadingSpinner = false;
@track newRecord = false;
@track editRecord = false;
@track viewRecord = false;
@track sortBy;
@track sortDirection;
@track emptyList = false;
@track error;
@track firstName;
@track lastName;
@track email;

// non-reactive variables

// retrieving the data using wire service
@wire(getContatcs, { sourceAccount: '$recordId' })
relations(result) {
this.refreshTable = result;
if ( { =;
this.emptyList = true;

handleSortdata(event) {
// field name
this.sortBy = event.detail.fieldName;
// sort direction
this.sortDirection = event.detail.sortDirection;
// calling sortdata function to sort the data based on direction and selected field
this.sortData(event.detail.fieldName, event.detail.sortDirection);

sortData(fieldname, direction) {
// serialize the data before calling sort function
let parseData = JSON.parse(JSON.stringify(;
// Return the value stored in the field
let keyValue = (a) => {
return a[fieldname];
// cheking reverse direction
let isReverse = direction === 'asc' ? 1 : -1;
// sorting data
parseData.sort((x, y) => {
x = keyValue(x) ? keyValue(x) : ''; // handling null values
y = keyValue(y) ? keyValue(y) : '';

// sorting values based on direction
return isReverse * ((x > y) - (y > x));

// set the sorted data to data table data = parseData;


//To handle the row actions
handleRowActions(event) {
let actionName =;
let row = event.detail.row;
// eslint-disable-next-line default-case
switch (actionName) {
case 'delete':

//To create new record
createNewRecord() {
// open modal box
this.currentRecordId = '';
this.ShowModal = true;
this.isEditForm = true;
this.newRecord = true;

// handleing record edit form submit
handleSubmit() {
createContact({ firstName: this.firstName, lastName: this.lastName, email:, acntId: this.recordId })
.then(result => {
.catch(error => {
this.error = error.body.message;

// refreshing the datatable after record edit form success
handleSuccess() {
// closing modal
this.ShowModal = false;
// showing success message
if (this.newRecord === true) {
this.dispatchEvent(new ShowToastEvent({
message: 'Contact Created sucessfully',
variant: 'success'

if (this.newRecord === false) {
this.dispatchEvent(new ShowToastEvent({
message: 'Contact updated sucessfully',
variant: 'success'
return refreshApex(this.refreshTable);

//To delete the selected relations
deleteRelations(currentRow) {
let currentRecord = [];
this.showLoadingSpinner = true;

// calling apex class method to delete the selected contact
deletecontact({ deleteContactIds: currentRecord })
.then(result => {
this.showLoadingSpinner = false;

// showing success message
this.dispatchEvent(new ShowToastEvent({
message: 'Contatact Deleted sucessfully',
variant: 'success'

// refreshing table data using refresh apex
return refreshApex(this.refreshTable);

.catch(error => {
this.dispatchEvent(new ShowToastEvent({
message: error.message,
variant: 'error'

//Event to track the First Name field
firstNameChange(event) {
this.firstName =;
this.error = '';

//Event to track the last Name field
lastNameChange(event) {
this.lastName =;
this.error = '';

//Event to track the Email field
emailChange(event) { =;
this.error = '';

// closing modal box
closeModal() {
this.ShowModal = false;
this.newRecord = false;
this.editRecord = false;
this.viewRecord = false;
this.error = '';



<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="">
<targetConfig targets="lightning__RecordPage">


Demo :


  1. Can You include pagination and edit function in this code?

    1. hello did u get that with pagination and edit? if u got this pls help me

    2. hello did u get that with pagination and edit? if u got this pls help me

    3. This comment has been removed by the author.

  2. Try installing below pacakges and you can see some examples with pagination - latest with pagination - old without pagination

  3. Add editable=true in ligtning-datatable

    { label: 'First Name', fieldName: 'FirstName', type: "string", sortable: true , editable=true },