Similar to this post, but the accepted answer is not solving my issue. Based on my troubleshooting (see below), it seems like the inherited property is getting set before the LWC rerenders the child component, and the child doesn't recognize the updated value.
I have an LWC with a series of screens. On one of the screens, a user can select records in a lightning-datatable. The lightning-datatable lives on a child component that is conditionally rendered by the parent.
When the Next button is clicked, the child component publishes a 'next' event, where the parent LWC captures the selected records in the event payload. The idea is to then parse the record Ids and store them in selectedVenueIds, but I'm currently hardcoding it to an Id I know exists in the list. selectedVenueIds is passed from the parent to the child component, mapping to the selected-rows property of lightning-datatable. However, when selecting records, clicking next & then back (returning to the datatable), there are no rows selected (even though this.selectedVenues is populated w/ a valid Id).
Parent Component
Conditionally-rendered child:
<template if:true={showSelectVenueScreen}>
<c-select-venues columns={columns} prospect-venues={prospectVenues} selected-venues={selectedVenueIds} onprevious={handlePreviousEvent} onnext={handleNextEvent}></c-select-venues>
</template>
Event handlers
handlePreviousEvent(event) {
if(this.screen == SELECT_VENUE_SCREEN) {
this.selectedVenues = undefined;
this.selectedVenueIds = undefined;
this.dispatchEvent(new CustomEvent('reset'));
} else if(this.screen == VALIDATE_SHIPPING_ADDRESS_SCREEN) {
this.screen = SELECT_VENUE_SCREEN;
/*let thisobj = this;
function f() {
thisobj.selectedVenueIds = ["001DS00001BP7vsYAD"];
console.log('*** after');
}
console.log('*** before');
setTimeout(f, 1000);*/
} else if(this.screen == ADD_VENUE_CONTACT_SCREEN) {
this.screen = VALIDATE_SHIPPING_ADDRESS_SCREEN;
} else if(this.screen == COLLECT_BUNDLES_TO_SHIP_SCREEN) {
this.screen = ADD_VENUE_CONTACT_SCREEN;
}
}
handleNextEvent(event) {
if(this.screen == SELECT_VENUE_SCREEN) {
// this.selectedVenueIds = event.detail.map(row => row['Id']);
this.selectedVenueIds = ["001DS00001BP7vsYAD"];
this.screen = VALIDATE_SHIPPING_ADDRESS_SCREEN;
} else if(this.screen == VALIDATE_SHIPPING_ADDRESS_SCREEN) {
this.screen = ADD_VENUE_CONTACT_SCREEN;
} else if(this.screen == ADD_VENUE_CONTACT_SCREEN) {
this.screen = COLLECT_BUNDLES_TO_SHIP_SCREEN;
}
}
get showSelectVenueScreen() {
return this.screen == SELECT_VENUE_SCREEN;
}
Child Component
HTML:
<template>
<lightning-card>
<div class="slds-box slds-m-bottom_large">
<lightning-datatable data={prospectVenues} columns={columns} selected-rows={selectedVenues} onrowselection={handleRowSelection} key-field="Id"></lightning-datatable>
</div>
</lightning-card>
<div slot="footer" class="slds-align_absolute-center">
<lightning-button variant="brand-outline" label="Previous" onclick={handlePreviousClick} class="slds-p-right_xx-small"></lightning-button>
<lightning-button variant="brand" label="Next" onclick={handleNextClick} disabled={disableNextButton} class="slds-p-left_xx-small"></lightning-button>
</div>
</template>
API property/click handlers:
@api selectedVenues;
handlePreviousClick() {
this.dispatchEvent(new CustomEvent('previous'));
}
handleNextClick() {
// ensure all selected venues have full addresses
let venuesWithoutAddress = [];
const selectedRows = this.template.querySelector("lightning-datatable").getSelectedRows();
selectedRows.forEach((row) => {
if(!row['ShippingStreet'] || !row['ShippingState'] ||!row['ShippingCity'] || !row['ShippingPostalCode'] || !row['ShippingCountry']) {
venuesWithoutAddress.push(row['Name']);
}
});
// don't proceed if invalid venues selected
if(venuesWithoutAddress.length) {
this.dispatchEvent(new ShowToastEvent({
title: 'Selected Venue(s) - Invalid Address',
message: 'The following venues do not have a valid address: ' + venuesWithoutAddress.join(', '),
variant: 'error'
}));
} else {
// let parent cmp know & send selected records
this.dispatchEvent(new CustomEvent('next', { detail: selectedRows }));
}
}
Troubleshooting/Things I've Tried/Noticed
- In handlePreviousEvent, I noticed I could not use template.querySelector('c-select-venues') immediately after setting this.screen = SELECT_VENUE_SCREEN - so I added a javascript timeout and hardcoded an assignment to this.selectedVenueIds. This works - after the user clicks the back button (returning to the select venue screen), the hardcoded row is selected. But obviously we don't want to rely on that.
- I confirmed the this.selectedVenueIds assignment in the parent's handleNextEvent handler is setting the value as expected, and that value is propagating to the child component. But for some reason, the lightning-datatable doesn't recognize the update and no rows are selected.