0

I am attempting to add a confirmation dialog (yes/no) for a predefined action on a LWC which does archiving. Basically need to show a popup saying do you confirm and the user selects yes/no to proceed. It seems to work but I had a question on some weird behavior. Please let me explain.

My confirm dialog LWC as follows:

<template>
    <lightning-card if:true={visible}>
        <div class="slds-container_small">
            <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">
                        <h2 id="modal-heading-01" class="slds-text-heading_medium slds-hyphenate">{title}</h2>
                    </header>
                    <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                        <p>{message}</p>
                    </div>
                    <footer class="slds-modal__footer">
                        <lightning-button variant="neutral"
                                          name="cancel"
                                          label={cancelLabel}
                                          title={cancelLabel}
                                          onclick={handleClick} ></lightning-button>
                        <lightning-button variant="brand"
                                          name="confirm"
                                          label={confirmLabel}
                                          title={confirmLabel}
                                          onclick={handleClick} ></lightning-button>
                    </footer>
                </div>
            </section>
            <div class="slds-backdrop slds-backdrop_open"></div>
        </div>
    </lightning-card>
</template>



import { LightningElement, api } from 'lwc';

export default class ConfirmationDialog extends LightningElement {

    @api visible; //used to hide/show dialog
    @api title; //modal title
    @api name; //reference name of the component
    @api message; //modal message
    @api confirmLabel; //confirm button label
    @api cancelLabel; //cancel button label
    @api originalMessage; //any event/message/detail to be published back to the parent component

    //handles button clicks
    handleClick(event){
        console.log('#1 I am in handleClick in confirmationDialog.js');
        let detail = {
            originalMessage: this.originalMessage,
            status: event.target.name
        };

        //dispatch a 'click' event so the parent component can handle it
        this.dispatchEvent(new CustomEvent('click', {detail: detail}));

    }


}

There is a parent LWC or 'manager' LWC that shows a list of rows with icons at the end that either say archive or edit or save. The icons are displayed by a child LWC called iconRenderer:

Each row on my parent LWC has a button renderer LWC that shows an icon.

<lightning-button-icon
      icon-name="utility:archive"
      variant="bare"
      size="large"
      alternative-text="Archive"
      class="slds-m-left_xx-small slds-p-top_xx-small slds-p-bottom_x-small slds-p-horizontal_xxx-small icon-border"
      title="Archive"
      onclick={handleArchiveClick}>
    </lightning-button-icon>

So when someone clicks on the archive icon the following handler happens on the icon rendered LWC:

handleArchiveClick() {
        let detail = {
            recordid: this.recordid,
            confirmDialog: true //as I want the confirmDialog to pop up
        };

        this.dispatchEvent(new CustomEvent('archive', {detail: detail}));
    }

Now on the parent LWC (manager) where all this happens, I have the handleArchive event handler that basically shows the confirm dialog if confirmDialog flag is set to true

handleArchive(event) {
        let detail = event.detail;

      if(detail.confirmDialog == true){

        console.log('detail.confirmDialog is true');

        this.originalMessage = JSON.stringify(event);
        this.showConfirmModal = true;

      }else{

        console.log('******* DO ARCHIVE NOW ********');
      }

I also have the following clickHandler right after the handleArchive and this is where my question is about:

    handleClick(event){
                if(event.detail !== 1){
                    console.log('Displaying event passed in handleClick');
                    console.log(JSON.stringify(event));
                    if(event.target.name === 'confirmModal'){
     
                    if(event.detail.status === 'confirm') {
    
                        let origEvent = JSON.parse(event.detail.originalMessage);
    
                        let detail = origEvent['detail'];
                        detail.confirmDialog = false;
    
                 
    // WHY DO I HAVE TO CALL THE HANDLER DIRECTLY AND WHY NOT JUST A DISPATCH EVENT OF THE SAME TYPE
    this.handleArchive(new CustomEvent(origEvent['type'], {detail: detail}));
                      
                    }else if(event.detail.status === 'cancel'){
                        console.log('cancel');
                    }
    
                this.showConfirmModal = false;

//ALSO WHY DOES handleClick() GET FIRED AGAIN AFTER I CHOSE YES OR NO AND IT CLOSES THE DIALOG? 
    
                }
            }
        }

The 2 questions I have are:

1). Instead of

this.handleArchive(new CustomEvent(origEvent['type'], {detail: detail})) 

when I do

this.dispatchEvent(new CustomEvent('archive', {detail: detail}))

how come that event does not end up getting handled by the handleArchive handler?

The only way I can get it to work is by calling the handler explicitly. Why is that?

2). When I click Yes or no, it fires a handleClick event again of detail = 1. Why is that click event happening? I have to filter it out using my if(event.detail !== 1) condition.

2
  • Is origEvent['type'] equal to 'archive'? What is the exact value of origEvent['type']? Did you try debug that?
    – Arthlete
    Commented Jun 15, 2020 at 18:33
  • Yes origEvent['type'] is 'archive' . It just does not get picked by the handleArchive(event) @Arthlete
    – kratos
    Commented Jun 15, 2020 at 18:35

1 Answer 1

2

this.dispatchEvent sends an event up the component hierarchy. Instead, use this.template.dispatchEvent. See Configure Event Propagation.

To bubble an event inside the component’s template, dispatch the event on an element in the template. The event bubbles up to the element’s ancestors inside the template only. When the event reaches the shadow boundary, it stops.

// myComponent.js
this.template.querySelector('div')
    .dispatchEvent(
        new CustomEvent('notify', { bubbles: true })
);
2
  • Very cool, I didn't know that. Would event.stopPropagation() amount for the same thing if called within one of the ancestors inside the component's template?
    – Arthlete
    Commented Jun 16, 2020 at 7:49
  • @Arthlete Yes, it would prevent the event from bubbling upwards any further than the handler which called this method.
    – sfdcfox
    Commented Jun 16, 2020 at 11:09

You must log in to answer this question.

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