1

I am currently working on an LWC project leveraging the Lightning Messaging System to share information between unrelated components all present on the same lightning page.

Lightning Page's User Interface

Here is the main use case:

  1. The houseCard component publishes the house's Id to remove from the houseTileList component through a Message Channel when the user clicks the Remove From List red button which is present on the right side of the page

houseCard.js

import { LightningElement, wire } from 'lwc';

//House__c Schema

import NAME_FIELD from '@salesforce/schema/House__c.Name'
import PICTURE_URL_FIELD from '@salesforce/schema/House__c.Picture_URL__c'
import SALESPRICE_FIELD from '@salesforce/schema/House__c.Sales_Price__c'
import NEIGHBORHOOD_FIELD from '@salesforce/schema/House__c.Neighborhood_Name__c'
import NB_OF_BED_FIELD from '@salesforce/schema/House__c.Nb_Of_Bed__c'
import NB_OF_BATH_FIELD from '@salesforce/schema/House__c.Nb_Of_Bath__c'
import NB_OF_FEATURES_FIELD from '@salesforce/schema/House__c.Nb_Of_Features__c'
import PROPERTY_TYPE_FIELD from '@salesforce/schema/House__c.Property_Type__c'


// getFieldValue function is used to extract field values
import {getFieldValue} from 'lightning/uiRecordApi'

//lightning message service
import {publish,subscribe, MessageContext, unsubscribe} from 'lightning/messageService'
import HOUSE_SELECTED_MESSAGE from '@salesforce/messageChannel/HouseSelected__c'
import HOUSE_REMOVE_FROM_LIST_MESSAGE from '@salesforce/messageChannel/HouseRemoveFromList__c'



export default class HouseCard extends LightningElement {

    /// load content for LMS
    @wire(MessageContext)
    messageContext

    //exposing fields to make them available in the template
    salesPrice = SALESPRICE_FIELD;
    nbOfBed = NB_OF_BED_FIELD;
    nbOfBath = NB_OF_BATH_FIELD;
    nbOfFeatures = NB_OF_FEATURES_FIELD;
    propertyType = PROPERTY_TYPE_FIELD;
    neighborhood = NEIGHBORHOOD_FIELD;

    //Id of House__c to display data
    recordId 

    // house fields displayed with specific format
    houseName;
    housePictureUrl;    

    //subscription reference for houseSelected
    houseSelectionSubscription 

    handleRecordLoaded(event){
        const {records} = event.detail;
        const recordData = records[this.recordId];
        this.houseName = getFieldValue(recordData, NAME_FIELD);
        this.housePictureUrl = getFieldValue(recordData, PICTURE_URL_FIELD);
    }

    connectedCallback(){
        this.subscribeHandler()
    }

    subscribeHandler(){
        this.houseSelectionSubscription = subscribe(this.messageContext, HOUSE_SELECTED_MESSAGE, (message)=>this.handleHouseSelected(message))
    }
    handleHouseSelected(message){
        this.recordId = message.houseId
    }

    handleRemoveFromList(){
        console.log("House Id To Remove " , this.recordId)
        publish(this.messageContext, HOUSE_REMOVE_FROM_LIST_MESSAGE, {
            houseId:this.recordId
         })
    }

    disconnectedCallback(){
        unsubscribe(this.houseSelectionSubscription)
        this.houseSelectionSubscription = null
    }
} 

houseTileList.js

import { LightningElement, wire, api, track } from 'lwc';
import getHouses from '@salesforce/apex/HouseController.getHouses'

// Lightning Message Service and a message channel
import {publish,subscribe,unsubscribe, MessageContext} from 'lightning/messageService'
import HOUSES_FILTERED_MESSAGE from '@salesforce/messageChannel/HousesFiltered__c'
import HOUSE_SELECTED_MESSAGE from '@salesforce/messageChannel/HouseSelected__c'
import HOUSE_DOUBLE_SELECTED_MESSAGE from '@salesforce/messageChannel/HouseDoubleSelected__c'
import HOUSE_REMOVE_FROM_LIST_MESSAGE from '@salesforce/messageChannel/HouseRemoveFromList__c'


export default class HouseTileList extends LightningElement {

    @api recordId; 
    houses= [];
    error;
    filters = {}; 
    houseFilterSubscription;
    houseRemoveFromListSubscription;
    __removedId;
    __newHousesList=[];

    @wire(getHouses, {filters:'$filters'})
    housesHandler({data, error}){
        if(data){
            console.log(data);
            this.houses = data;
        }
        if(error){
            this.error = error;
            console.error(error);
        }
    }

     /**Load context for LMS */
     @wire(MessageContext)
     messageContext

     connectedCallback(){
         this.subscribeHandler();
     }

     subscribeHandler(){
         this.houseFilterSubscription = subscribe(this.messageContext, HOUSES_FILTERED_MESSAGE, (message)=>this.handleFilterChanges(message));
         this.houseRemoveFromListSubscription = subscribe(this.messageContext, HOUSE_REMOVE_FROM_LIST_MESSAGE, (message)=>this.handleRemoveFromList(message));
     }

     handleFilterChanges(message){
         console.log(message.filters)
         this.filters ={...message.filters}
     }

     handleRemoveFromList(message){
        console.log('Received Id', message.houseId)
        this.__removedId = message.houseId
        this.__newHousesList = Array.from(this.houses);
        console.log('Houses list before remove event: ', this.__newHousesList) 
        console.log('Removed Id', this.__removedId)
        
     }

     handleHouseSelected(event){
        console.log("selected house Id " , event.detail)
        publish(this.messageContext, HOUSE_SELECTED_MESSAGE, {
            houseId:event.detail
         })
     }

     handleDoubleSelected(event){

        console.log("Double selected house Id " , event.detail)
        publish(this.messageContext, HOUSE_DOUBLE_SELECTED_MESSAGE, {
            houseId:event.detail
         })

    }

     disconnectedCallback(){
        unsubscribe(this.houseFilterSubscription)
        unsubscribe(this.houseRemoveFromListSubscription)
        this.houseFilterSubscription = null
        this.houseRemoveFromListSubscription = null
    }
}
  1. The houseTileList component subscribes to the Message Channel and receives the house's Id to remove

My challenge is the following:

  1. The houses property in houseTileList component contains all the houses displayed on the UI side

  2. I would like to remove the received Id form the houses property

  3. Make sure that my components perceives the mutation and reactively re-renders the updtaded property on the UI side

Here are the steps that I followed in order to achieve this:

  • In the houseCard.js file
  1. Verified that the id to remove is properly sent from the houseCard component when the button is clicked

enter image description here

  • In the houseTileList.js file -> handleRemoveFromList method
  1. Verified that the Id to remove is received by the houseTileList component

enter image description here

  1. Tried to filter out this specific Id from the houses array of objects using the following code:
        console.log('Houses list before filter: ', this.houses)// Verifying Initial Houses List's format and data content
        this.__newHousesList = [...this.houses];// Shallow copy of the original array
        console.log('New Houses list before filter: ', this.__newHousesList) // Verifying New Houses List's format and data content
        this.houses = this.__newHousesList.filter(item => item.Id !== this.__removedId)// Filter operation on New Houses List to remove Id 
        console.log('Houses list after the filter operation: ', this.houses)// Verifying Updated Houses List's format and data content

Here the console's output:

  1. Initial houses list is populated

enter image description here

  1. Shallow copy and filter operations are not working

enter image description here

It looks like the shallow copy I attempted is not working as I am receiving a Proxy with an empty array. This makes the subsequent filter operation non functional and the houses array is not updated accordingly.

I was wondering if someone could provide me with some insights, best practices or assistance regarding this problem?

Thanks!

1 Answer 1

0

The first thing you need to do is add the @track decorator to houses. Arrays and objects don't automatically update in the UI without it. https://developer.salesforce.com/docs/component-library/documentation/en/lwc/reference_decorators

As to why the shallow copy isn't working, I'm not sure... it ought to be, as I've used the same pattern before.

1
  • Thank you Rob. The @track decorator solved the issue! Many Thanks.
    – Yann M.
    Commented Feb 24, 2023 at 20:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .