0

I'm having an issue getting my LWC component with multiple datatables to refresh.

Background:

I'm displaying lectures in multiple data tables, organized by date the lecture was created. So, if there are two lectures created on April 21st, and three on April 23rd. There will be 2 data tables, with 2 and 3 lectures in each table respectively.

There is a "New Lecture" button on the main component which allows the user to create a lecture (by selecting a date in a modal). Once the user creates a lecture, I would like this lecture to show up in the data table without a page refresh. Since each data table is organized by date, it's possible that the lecture may go in an existing data table or a new one will have to be created.

My Issue:

The refreshApex method kinda works - If I create a new lecture with a new date, it will create a new table with my lecture. But, if I create a lecture with the same date as an existing datatable, it will not insert this lecture into the table.

My Question:

Should I be trying something different besides refreshApex for my use case? or is this not wired up correctly between my child and parent components?

Objects and Components

  1. Course__c: Main object which where the LWC is displayed.
  2. Lecture__c: Lookup to Course Object. These are the records in the datatables
  3. lectureDates.apxc: Returns the dates the lecture was created
  4. lectureData.apxc Returns the actual data to populate in the data table
  5. CourseComponent.js: A "Parent" component that pulls the dates from apex and iterates through them and displays the lectures in data tables, organized by date. The data tables are each in their own custom component.
  6. LectureDatatable.js: A "Child" component. This custom component is a data table which will display all the courses for each date

CourseComponent.js (Parent)

import { LightningElement } from 'lwc';
import lectureDates from '@salesforce/apex/CourseController.courseDates';
import { refreshApex } from '@salesforce/apex';

export default class CourseComponent extends LightningElement {

@api recordId;
@api createdDate;
wiredLectureDates;

@wire(lectureDates, { recordId: '$recordId'})
displayLectureDates(dates) {
  this.wiredLectureDates = dates;
}

handleNewLecture() {
  createLecture.open({CourseID : this.recordId }).then(result => {
    refreshApex(this.wiredDates);
  }      
  
}

lectureDates.apxc

@AuraEnabled(cacheable=true)
public static List<DateWrapper> lectureDates(Id recordId) {
   Set<Date> dateSet = new Set<Date>();

   List<Lectures__c> lectures = new List<Lectures__c>([
     select title__c, createddate from lectures__c
   ]);

   for (Lectures__c lecture : lectures) {
     dateSet.add(lecture.createddate);
   }

   for (Date lectureDate : dateSet) {
        DateWrapper dateWrapper = new DateWrapper();
        
        dateWrapper.LectureCreatedDate = lectureDate;
        dateWrapper.CourseId = recordId;
        
        dateWrapperList.add(dateWrapper);
    }

    return dateWrapperList;
}

CourseComponent.html (Parent)

<template>
  <div>
   <lightning-button label="New Lecture" onclick={handleNewLecture}> 
   </lightning-button>
  </div>
  <template for:each={wiredLectureDates.data} for:item="date">
    <lightning-card key={date.LectureCreatedDate}>
      <lightning-accordion>
        <lightning-accordion-section name={date.LectureCreatedDate} label={date.LectureCreatedDate}>

         <c-lecture-datatable 
           created-date={date.LectureCreatedDate}
           record-id={date.CourseID}>
         </c-lecture-datatable>

        </lightning-accordion-section>
        </lightning-accordion>
      </div>
    </lightning-card>
   </template>

LectureDatatable.js (Child)

 import lectureData from '@salesforce/apex/CourseController.lectureData';

 export default class LectureDatatable extends LightningElement {
   @api createdDate;
   @api recordId;
   @track columns = [ {label: 'Course Title' }];
   @track lectureList;

   connectedCallback() {
     lectureData({ recordId: this.recordId, createdDate: this.createdDate }).then(result => {
     this.lectureList = result.map(item => {
      let lectureRecord = Object.assign({},item);
      return lectureRecord;
     }
   }
 }

LectureDatatable.html (Child)

<template>
  <lightning-datatable
      data={lectureList} 
      columns={columns}
      key-field="Id"
    </lightning-datatable>
</template>

lectureData.apxc

@AuraEnabled(cacheable=true)
public static List<LectureWrapper> lectureData(Id recordId) {
   List<LectureWrapper> lectureWrapperList = new List<LectureWrapper>();

   List<Lectures__c> lectures = new List<Lectures__c>([
     select title__c from lectures__c
   ]);

   for (Lectures__c lecture : lectures) {
     LectureWrapper lectureWrapper = new LectureWrapper();
     LectureWrapper.Title = lecture__c;

     lectureWrapperList.add(LectureWrapper);
   }

    return lectureWrapperList;
}

1 Answer 1

1

LectureDatatable is only querying its data once, when the table first comes into existence (connectedCallback). There's a few ways to fix this, but the easiest fix from where you are would be to toggle the display while you load records.

<template>
  <div>
   <lightning-button label="New Lecture" onclick={handleNewLecture}> 
   </lightning-button>
  </div>
  <template lwc:if={loading}>
    <lightning-spinner alternative-text="Loading..."></lightning-spinner>
  </template>
  <template lwc:else for:each={wiredLectureDates.data} for:item="date">
    <lightning-card key={date.LectureCreatedDate}>
      <lightning-accordion>
        <lightning-accordion-section name={date.LectureCreatedDate} label={date.LectureCreatedDate}>

         <c-lecture-datatable 
           created-date={date.LectureCreatedDate}
           record-id={date.CourseID}>
         </c-lecture-datatable>

        </lightning-accordion-section>
        </lightning-accordion>
      </div>
    </lightning-card>
   </template>
</template>

Then, in your controller:

loading = true;
@wire(lectureDates, { recordId: '$recordId'})
displayLectureDates(dates) {
  this.wiredLectureDates = dates;
  this.loading = !dates.data;
}
handleNewLecture() {
  createLecture.open({CourseID : this.recordId }).then(result => {
    this.loading = true;
    refreshApex(this.wiredLectureDates);
  }      
}

Now, your data will be briefly removed while the new data loads, and then pop back in when it's done--and all your data will be rendered anew.

11
  • wow! thank worked. Thank you so much! Commented Apr 21, 2023 at 18:11
  • 1
    @learnerforlife That's odd. I feel like that should have worked. The only change was the lwc:if/lwc:else. The spinner does show briefly, right? I did just realize that my example was calling refreshApex on the wrong variable name. Make sure they match.
    – sfdcfox
    Commented Apr 21, 2023 at 18:20
  • 1
    @learnerforlife The recommended strategy would be to query all the lectures in the parent component, then manipulate the data to split them into the various tables. This would greatly reduce the number of callouts your components need.
    – sfdcfox
    Commented Apr 21, 2023 at 18:55
  • 1
    @learnerforlife It'd be nice to see what all the code looks like now. Can you post the new code?
    – sfdcfox
    Commented Apr 28, 2023 at 20:57
  • 1
    @learnerforlife Excellent! Glad I was able to help a bit :D
    – sfdcfox
    Commented Apr 28, 2023 at 21:23

You must log in to answer this question.

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