2

I have created lightning data table MyLightningDataTable with a custom data type. This custom datatable is a child component of MyDataGroup component and MyDataGroup is a child of MyData component.

enter image description here

MyData component's getData method retrieves date from back-end. Then processes data and generates processed_data object as follows.

    processed_data = [
        {group_id : 'group_name1',
         data     : [data1Obj1, data1Obj2, ...]},

        ...
    ];

Using these data it dynamically generated MyGroupData components(which has a MyLightningDataTable component). When Custom data type of this datatable fires an event I need to call the getData method of MyData component again. How can I achieve this?

Code segment relevant to this are indicated follow.

MyData.js

    import { LightningElement, track } from 'lwc';

    import getAccounts from '@salesforce/apex/AccountController.getAccounts'

    import FI_MID_ACCOUNT_FID_ANNUAL_REVENUE from '@salesforce/schema/Account.AnnualRevenue';
    import FI_MID_ACCOUNT_FID_DESCRIPTION from '@salesforce/schema/Account.Description';

    export default class MyData extends LightningElement {
        @track accounts;
        @track editableFields = [
            FI_MID_ACCOUNT_FID_ANNUAL_REVENUE,
            FI_MID_ACCOUNT_FID_DESCRIPTION
        ];

        @track columns = [
            {label: 'Name', fieldName: 'Name', type: 'editableRecord', typeAttributes: { 
                    recordId:  {fieldName: 'Id'},                                                                                                
                    objApiName:'Account',                                                                                           
                    fieldList: this.editableFields,
                    updatedone: this.getData                                                                                                 
                },
            ...
        ];

        connectedCallback() {
            this.getData();
        }

        getData(){
            getAccounts()
            .then(result => {
                this.accounts = result;
                this.processAccounts(this.accounts);
            })
            .catch(error => {
                this.error = error;
                this.accounts = undefined;
            });
        }

        processAccounts() {
            //generates processed_data object.
        }
    }

MyData.html

    <template>
        <template if:true={processed_data}>
            <lightning-accordion allow-multiple-sections-open onsectiontoggle={handleSectionToggle}
                active-section-name={}>
                <template for:each={processed_data} for:item="account_group">
                    <lightning-accordion-section key={account_group.group_id} name={account_group.group_id} label={account_group.group_id}>
                        <c-my-data-group
                            group-id={audit_group.group_id}
                            data-list={audit_group.data}
                            columns={columns}>
                        </c-my-data-group>
                    </lightning-accordion-section>
                </template>
            </lightning-accordion>
        </template>
    </template>

MyDataGroup.js

    export default class CurrentAuditsGroup extends LightningElement {
        @api groupId;
        @api dataList;
        @api columns;
    }

MyDataGroup.html

    <templete>
        <c-current-audits-lightning-table key={groupId} data={dataList} key-field="Id" columns={columns}>
        </c-current-audits-lightning-table>
    </template>

editableRecord.js

    import { LightningElement, api, track } from 'lwc';
    import { ShowToastEvent } from 'lightning/platformShowToastEvent';

    export default class EditableRecord extends LightningElement {
        @api displayText;
        @api recordId;
        @api objApiName;
        @api fieldList;

        @track openViewRecord;

        expandRecord() {
            this.openViewRecord = true;
        }

        closeViewRecord() {
            this.openViewRecord = false;
        }

        onUpdateSuccess() {
            this.dispatchEvent(
                new ShowToastEvent({
                    title: 'Success',
                    message: 'Records updated',
                    variant: 'success'
                })
            );
            // This event should be caught at MyData
            this.dispatchEvent(new CustomEvent('refresh'));

            this.closeViewRecord();
        }
    }

editableRecord.html

    <template>
        <span class="slds-text-link_faux">
            <lightning-formatted-text onclick={expandRecord} value={displayText} linkify></lightning-formatted-text>
        </span>

        <template if:true={openViewRecord}>
            <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">
                    <header class="slds-modal__header">
                        <button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse" title="Close" onclick={closeViewRecord}>
                            <lightning-icon icon-name="utility:close" size="medium">
                            </lightning-icon>
                            <span class="slds-assistive-text">Close</span>
                        </button>
                        <h2 id="confirmation-modal-heading-1" class="slds-text-heading_medium slds-hyphenate">{displayText}</h2>
                    </header>
                    <div class="slds-modal__content slds-p-around_large" id="confirmation-modal-content-id-1">
                            <lightning-record-edit-form record-id={recordId}
                            object-api-name={objApiName} onsuccess={onUpdateSuccess}>
                                <lightning-messages>
                                </lightning-messages>
                                <template for:each={fieldList} for:item="field">
                                    <lightning-input-field key={field.fieldApiName} field-name={field.fieldApiName}>
                                    </lightning-input-field>
                                </template>
                                <lightning-button
                                    class="slds-m-top_small"
                                    variant="brand"
                                    type="submit"
                                    name="update"
                                    label="Update">
                                </lightning-button>
                            </lightning-record-edit-form>
                    </div>
                    <!-- <footer class="slds-modal__footer">
                        <lightning-button label="Cancel" variant="neutral" onclick={closeViewRecord}></lightning-button>
                    </footer> -->
                </div>
            </section>
                <div class="slds-backdrop slds-backdrop_open"></div>
        </template>
    </template>

MyLightningDataTable.js

    import LightningDatatable from 'lightning/datatable';
    import editableRecordHtml from './editableRecordTemplate.html';
    export default class CurrentAuditsLightningTable extends LightningDatatable {

        static customTypes = {
            editableRecord: {
                template        : editableRecordHtml,
                typeAttributes  : ['displayText', 'recordId', 'objApiName', 'fieldList', 'updatedone' ]
            }
        };
    }

MyLightningDataTable.html

    <template>
    </template>

editableRecordTemplate.html

    <template>
        <c-editable-record
            display-text={value}
            record-id={typeAttributes.recordId}
            obj-api-name={typeAttributes.objApiName}
            field-list={typeAttributes.fieldList}
            onupdated={typeAttributes.updatedone}>
        </c-editable-record>
    </template>

UPDATE

I was able to set an getData() function in typeAttributes and call it at onupdated() event. This function is working fine when it is called at connectedCallback(). But when it is calling with the event, javascript stops with an error saying processAccount() function is undefined.

I have updated the code accordingly.

Any idea?

1

Finally got through it. I had to dispatch event with composed and bubbles attributes as follows.

const event = CustomEvent('refresh', {
    composed: true,
    bubbles: true
});
this.dispatchEvent(event);

Then I added event binding at MyDataGroup.html

<c-current-audits-lightning-table
    key={groupId}
    data={dataList}
    key-field="Id"
    columns={columns}
    onrefresh={refreshHandler}>
</c-current-audits-lightning-table>

After this setup when I clicked the button, refreshHandler() at MyDataGroup.js was called as expected.

Even though this solved my problem, I still do not know why I needed to set bubbles and composed attributes.

0

Maybe try:

  1. Create an event handler on the parents.
  2. Add the on"mycustomevent" prop on your components
  3. Dispatch event with payload from children
<!-- eventSimple.html -->
<template>
    <lightning-card title="EventSimple" icon-name="custom:custom9">
        <div class="slds-m-around_medium">
            <p class="slds-m-vertical_medium content">Page {page}</p>
            <c-paginator 
              onprevious={previousHandler} <!--these are the handlers on the parent-->
              onrefresh={refreshHandler}
            ></c-paginator>
        </div>
    </lightning-card>
</template>

Here is the parent JS:

// eventSimple.js
import { LightningElement, track } from 'lwc';

export default class EventSimple extends LightningElement {
    @track page = 1;

    previousHandler() {
        if (this.page > 1) {
            this.page = this.page - 1;
        }
    }

    refreshHandler() {
        this.page = this.page + 1;
    }
}

Here is the Child JS:

// paginator.js
import { LightningElement } from 'lwc';

export default class Paginator extends LightningElement {
    previousHandler() {
        this.dispatchEvent(new CustomEvent('previous')); //this is the prop without 'on'
    }

    nextHandler() {
        this.dispatchEvent(new CustomEvent('refresh')); //this is the prop without 'on'
    }
}
  • Yes, I was able to handle events from child according to the way you've mentioned. But in my case event fires from actually from a data type. It seems that is pretty different. It was not working for me as usual. – Isuru Buddhika Herath Oct 28 at 1:34
  • Do you mean that you are trying to dispatch data from an event? you can send the data in the detail object: {detail: { Stuff }} – Luigi Campbell Oct 28 at 20:49
  • Actually not. See my editableRecord.js It dispatch an event called refresh. i need to handle that event at MyData.js – Isuru Buddhika Herath Oct 29 at 12:32
  • I think either you're not reading the response or I am not understanding your question: use an attribute called onrefresh to capture the event – Luigi Campbell Oct 30 at 1:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.