Custom Multi Lookup LWC - Refresh Page After Record Edit -> Save

185 Views Asked by At

Greetings [Please Skip To The End To Get Summary Only]

I am trying to develop a custom multi-lookup component from scratch. The final product until now is this. Its end goal is to create a list of contacts for a marketing list. Users will be able to see a list of Available Conacts, based on some criteria, and add them to the list (Added Contacts) enter image description here

The UI of the Contact List is created using this code

<template>
<lightning-card title="Contact List">
    <div class="slds-m-around_medium" style="display: flex;justify-content: space-between;">
        <div>
            <template if:true={contacts}>
                <table class="slds-table slds-table_bordered slds-table_cell-buffer">
                    <thead>
                        <tr>
                            <h6>Available Contacts</h6>
                        </tr>
                        <tr>
                            <th scope="col">First Name</th>
                            <th scope="col">Last Name</th>
                            <th scope="col">Email</th>
                            <th scope="col">Phone</th>
                            <th scope="col">Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        <template for:each={contacts} for:item="contact">
                            <tr key={contact.Id}>
                                <td>{contact.FirstName}</td>
                                <td>{contact.LastName}</td>
                                <td>{contact.Email}</td>
                                <td>{contact.Phone}</td>
                                <td>
                                    <lightning-button label="Add To List" variant="brand"
                                        data-contact-id={contact.Id} onclick={handleAddToList}>
                                    </lightning-button>
                                    <!-- <lightning-button label="Add To List" variant="brand"
                                        data-contact-id={contact.Id} onclick={handleAddToList}
                                        disabled={addedContacts.has(contact.Id)}>
                                    </lightning-button> -->
                                </td>
                            </tr>
                        </template>
                    </tbody>
                </table>
            </template>
            <template if:true={contacts.error}>
                <div class="slds-text-color_error">
                    An error occurred while loading Contacts.
                </div>
            </template>
        </div>
        <div>
            <template if:true={addedContacts}>
                <table class="slds-table slds-table_bordered slds-table_cell-buffer">
                    <thead>
                        <tr>
                            <h6>Added Contacts</h6>
                        </tr>
                        <tr>
                            <th scope="col">First Name</th>
                            <th scope="col">Last Name</th>
                            <th scope="col">Email</th>
                            <th scope="col">Phone</th>
                            <th scope="col">Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        <template for:each={addedContacts} for:item="addedcontact">
                            <tr key={addedcontact.Id}>
                                <td>{addedcontact.FirstName}</td>
                                <td>{addedcontact.LastName}</td>
                                <td>{addedcontact.Email}</td>
                                <td>{addedcontact.Phone}</td>
                                <td>
                                    <lightning-button label="Remove" variant="destructive"
                                        data-addedcontact-id={addedcontact.Id} onclick={handleRemoveFromList}>
                                    </lightning-button>
                                    <!-- <lightning-button label="Add To List" variant="brand"
                                        data-contact-id={contact.Id} onclick={handleAddToList}
                                        disabled={addedContacts.has(contact.Id)}>
                                    </lightning-button> -->
                                </td>
                            </tr>
                        </template>
                    </tbody>
                </table>
            </template>
            <template if:true={contacts.error}>
                <div class="slds-text-color_error">
                    An error occurred while loading Contacts.
                </div>
            </template>
        </div>
    </div>
    <lightning-button label="Save" variant="brand" onclick={handleMarketingListUpdate}>
    </lightning-button>
</lightning-card>
</template>

All the available contacts will be shown on the left side, excluding the ones already there on the right side. When I move an item to the right, and then click save, the contact IDs of the right side are stored in a comma-separated variable string of IDs.

My apex class looks like this

public with sharing class MarketingListContactsController {
@AuraEnabled
public static List<Contact> getContacts(String recordId) {
    // Query the Marketing List to get the Selected_Contact_Ids__c field
    Marketing_List__c marketingList = [SELECT Selected_Contact_Ids__c, Countries__c, Met__c FROM Marketing_List__c WHERE Id =: recordId];
    List<Contact> contacts = new List<Contact>();

    List<String> selectedCountries = marketingList.Countries__c.split(';');
    if (!String.isBlank(marketingList.Selected_Contact_Ids__c)) {
        // Split the comma-separated IDs and convert them to a list
        List<String> contactIds = marketingList.Selected_Contact_Ids__c.split(',');
        
        // Query for the Contact records that are not in the extracted IDs
        contacts = [SELECT Id, FirstName, LastName, Email, Phone
            FROM Contact
            WHERE Id NOT IN :contactIds
            AND Country__c IN :selectedCountries
            AND Met__c = :marketingList.Met__c];
    } else {
        // If no contact IDs are specified, filter only by Met__c and Countries__c
        contacts = [SELECT Id, FirstName, LastName, Email, Phone
            FROM Contact
            WHERE Country__c IN :selectedCountries
            AND Met__c = :marketingList.Met__c];
    }

    return contacts;
}

@AuraEnabled
public static List<Contact> getStoredContacts(String recordId) {
    List<Contact> contacts = new List<Contact>();

    // Query the Marketing List to get the Selected_Contact_Ids__c field
    Marketing_List__c marketingList = [SELECT Selected_Contact_Ids__c FROM Marketing_List__c WHERE Id =:recordId];

    List<String> contactIds = marketingList.Selected_Contact_Ids__c.split(',');

    contacts = [SELECT Id, FirstName, LastName, Email, Phone FROM Contact WHERE Id IN :contactIds];

    return contacts;
}

@AuraEnabled
public static void updateMarketlingList(List<String> contactIds, String recordId) {
    Marketing_List__c parentMarketingList = [Select Id, Selected_Contact_Ids__c from Marketing_List__c where Id =: recordId];
    System.debug('Hello wordl');
    System.debug(recordId);
    System.debug(contactIds);
    // Remove open and close parentheses
    String stringWithoutParentheses = contactIds.toString().replace('(', '').replace(')', '');

    // Remove spaces
    String stringWithoutSpaces = stringWithoutParentheses.replaceAll(' ', '');

    // List<Contact> contactsToUpdate = new List<Contact>();
    // parentMarketingList.Selected_Contact_Ids__c = '';
    parentMarketingList.Selected_Contact_Ids__c = stringWithoutSpaces;
    update parentMarketingList;

}
}

The javascript controller looks like this

import { LightningElement, track, api,wire } from 'lwc';
import getContacts from '@salesforce/apex/MarketingListContactsController.getContacts';
import getStoredContacts from '@salesforce/apex/MarketingListContactsController.getStoredContacts';
import updateMarketlingList from '@salesforce/apex/MarketingListContactsController.updateMarketlingList';


export default class ContactList extends LightningElement {
@api recordId;
@track contacts = new Set();
@track addedContacts = new Set();

connectedCallback() {
    this.loadContacts();
    this.loadStoredContacts();
}

loadContacts() {
    getContacts({recordId: this.recordId})
        .then(result => {
            this.contacts = new Set(result);
            console.log('All contacts',this.contacts);
        })
        .catch(error => {
            console.error('Error loading Contacts', error);
        });
    
}
loadStoredContacts() {
    getStoredContacts({recordId: this.recordId})
    .then(result => {
        this.addedContacts = new Set(result);
        console.log('Added contacts', this.addedContacts);
    })
    .catch(error => {
        console.log('Error loading stored contacts', error);
    })
}

handleAddToList(event) {
    const contactId = event.currentTarget.dataset.contactId;
    const arr = []
    this.contacts.forEach(setItem => {
        if(setItem.Id === contactId) {
            this.addedContacts.add(setItem);
        } else {
            arr.push(setItem)
        }
    });
    this.contacts = new Set(arr);
}

handleRemoveFromList(event) {
    const contactId = event.currentTarget.dataset.addedcontactId;
    const arr = []
    this.addedContacts.forEach(contact => {
        if(contact.Id === contactId) {
            this.contacts.add(contact)
        } else {
            arr.push(contact)
        }
    })
    this.addedContacts = new Set(arr)
}

handleMarketingListUpdate(event) {
    // Use the map method to extract the IDs from the objects
    const idArray = Array.from(this.addedContacts).map(item => item.Id);
    const strArr = [];
    
    // Use the join method to create a comma-separated string
    const commaSeparatedIds = idArray.join(',');
    strArr.push(commaSeparatedIds)
    const stringArr = new Set(idArray);
    console.log(stringArr)
    updateMarketlingList({contactIds: idArray, recordId: this.recordId})
    .then( result => {  
        console.log("Contacts Updated succesfully.");
    })
    .then(() => {
        this.loadContacts();
        this.loadStoredContacts();
    })
    
    .catch( error => {
        console.log('Error ', error);
    })
}

}

The overall flow can be summarized in this manner

Marketing List Record Loads

  1. loadContacts(javascript) method calls getContacts(apex) method.
  • getContacts checks the filters form the record's custom fields Countries__c and Met__c, checks the string of contact IDs in the custom field Selected_Contact_Ids__c, and returns an array of contacts
  • contacts variable is populated
  • they are displayed in the "Available Contacts" section.
  1. loadStoredContact(javascript) method calls getStoredContacs(apex) method
  • getStoredContacts returns the array of contacts based don't the comma separated array of strings stored in Selected_Contact_Ids__c
  • addedContacts variable is populated
  • they are displayed in the Added Contacts section

Click on "Add To List"

  • handleAddToList appends the id of the clicked contact to the addedContacts variable, removes the id from the contacts variable

Click on "Remove"

  • handleRemoveFromList removes the id of the clicked contact from the addedContacts, adds it to the contacts variable

Click on "Save"

  • handleMarketingListUpdate(javascript) method calls the updateMarketlingList(apex) method
  • Selected_Contact_Ids__C field is updated with current string of comma separated IDs from addeContacts variable

MY PROBLEM Since I'm saving the record with my filters i.e. normal record update, the page doesn't refresh. If it doesn't refresh, my UI does not reflect the change in the Available Contact section. When I refresh manually, it does.

My Question How do I refresh the record page, when the user updates the Countries__c or Met__c field?

I know this might not be the most efficient way of doing this, so I'm open to ideas. If you read this far, you're an absolute legend. Would highly appreciate if you can share your opinion on this. Thanks!

0

There are 0 best solutions below