Close lightning component modal from within the modal

I have a modal that allows a user to select some options and then upload a file. I want to close the modal as soon as the upload completes (the user clicks the Done button). So here’s my code:

Parent markup

<lightning:overlayLibrary aura:id="overlayLib"/>
...
<lightning:buttonIcon iconName="utility:upload" 
                      variant="border" 
                      alternativeText="Upload Files" 
                      title="Upload Files"
                      onclick="{!c.handleShowModal }" disabled="{!v.disabled}"/>

Parent controller

handleShowModal: function(component, evt, helper) {
    var modalBody;
    var modalHeader;
    var recordId = component.get("v.myObjId");
    $A.createComponent("c:fileUploadModal", {relatedRecordId: recordId},
        function(content, status) {
            if (status === "SUCCESS") {
                modalBody = content;
                modalHeader = $A.get("$Label.c.Upload_Modal_Header");
                component.find('overlayLib').showCustomModal({
                   header: modalHeader,
                   body: modalBody, 
                   showCloseButton: true,
                   cssClass: "mymodal",
                   closeCallback: function() {
                       // Refresh our list of files
                       helper.retrieveDocs(component, event, helper);
                   }
               })
           }                               
        });
}

Modal markup

<lightning:fileUpload  name="fileUploader"
                       multiple="false"
                       accept="{!v.fileExtensions}"
                       recordId="{!v.relatedRecordId}"
                       onuploadfinished="{!c.handleUploadFinished }"/>

Modal controller:

handleUploadFinished: function (component, event) {
    var uploadedFiles = event.getParam("files");
    console.log(uploadedFiles[0].documentId); // See? it works.
    component.find("overlayLib").notifyClose();
}

Obviously the .notifyClose() isn’t working because component.find("overlayLib") returns undefined since that component does not have access to the parent component.
I tried document.getElementsByClassName('uiButton--modal-closeBtn')[0].click() but that doesn’t work because of Aura.
So how do I programmatically close the modal after the user acknowledges that their file has been uploaded successfully?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Final Edit:

Solution based on passing overlayLib as an attribute to dynamically created modal component.

Last idea that I had (and tested) is to pass overlayLib as an attribute when dynamically creating modal:

<aura:component implements="flexipage:availableForAllPageTypes">
    <aura:attribute name="lib" type="Object"/>
    <lightning:fileUpload  name="fileUploader"
                           multiple="false"
                           accept="{!v.fileExtensions}"
                           recordId="{!v.relatedRecordId}"
                           onuploadfinished="{!c.handleUploadFinished }"/>  
</aura:component>


handleUploadFinished: function (component, event) {
    var uploadedFiles = event.getParam("files");
    console.log(uploadedFiles[0].documentId); // See? it works.
    component.get("v.lib").notifyClose();
}

Creating modal

handleShowModalFooter : function (component, event, helper) {
    var modalBody;
    var modalFooter;
    $A.createComponents([
        ["c:modalContent",{'lib':  component.find('overlayLib')}],
        ["c:modalFooter",{}]
    ],
    function(components, status){
        if (status === "SUCCESS") {
            modalBody = components[0];
            modalFooter = components[1];
            component.find('overlayLib').showCustomModal({
               header: "Application Confirmation",
               body: modalBody, 
               footer: modalFooter,
               showCloseButton: true,
               cssClass: "my-modal,my-custom-class,my-other-class",
               closeCallback: function() {
                   alert('You closed the alert!');
               }
           })
        }
    }
   );
}

Edit: Ok I didnt fully understand question, so I’m adding new answer with old one staying just for reference.

You can of course create footer for your modal with buttons that will handle modal close.

Example mainly from the docs:

Modal footer component:

<aura:component>
    <lightning:overlayLibrary aura:id="overlayLib"/>
    <lightning:button name="cancel" label="Cancel" onclick="{!c.handleCancel}"/>
    <lightning:button name="Close" label="Close" variant="brand" onclick="{!c.handleCancel}" disabled="true"/>
</aura:component>

Footer controller:

({
    handleCancel : function(component, event, helper) {
        //closes the modal or popover from the component
        component.find("overlayLib").notifyClose();
    }
})

Creating modal controller:

({
handleShowModalFooter : function (component, event, helper) {
    var modalBody;
    var modalFooter;
    $A.createComponents([
        ["c:modalContent",{}],
        ["c:modalFooter",{}]
    ],
    function(components, status){
        if (status === "SUCCESS") {
            modalBody = components[0];
            modalFooter = components[1];
            component.find('overlayLib').showCustomModal({
               header: "Application Confirmation",
               body: modalBody, 
               footer: modalFooter,
               showCloseButton: true,
               cssClass: "my-modal,my-custom-class,my-other-class",
               closeCallback: function() {
                   alert('You closed the alert!');
               }
           })
        }
    }
   );
}
})

I on purpose made one button disabled in a footer so you can enable that in your code

Method 2

Before I get to the answer, thank you very much to user1974566 for your assistance, you eventually led me to the correct solution which is as follows:

First of all (which I discovered towards the end), things change and the way to close a modal now is via promise. See this question. The correct solution is as provided by Oles Malkov. I’ll summarize it here.
On the parent component (the one that launched the modal) notifyClose() no longer does anything. I discovered this after I was eventually able to capture the event fired by the modal in the parent component (explained below) but it wasn’t closing the modal.
The correct way to do that is to save the promise returned by showCustomModal() as an aura:attribute and use that to close the modal.

Second, there is a way to subvert the component hierarchy that got subverted by the modal: APPLICATION events. That fired an event into the void of the application, regardless of the component hierarchy. This allowed my parent component to capture the event from the modal (which should have been its child) and close it.
Full solution:

Parent markup

<aura:attribute name="modalPromise" type="Aura.Action"/> <!--Save the promise from opening the file upload modal-->
<aura:handler event="c:fileUploaded" action="{!c.handleFileUploaded}"/>
<lightning:overlayLibrary aura:id="overlayLib"/>
...
<lightning:buttonIcon iconName="utility:upload" 
                  variant="border" 
                  alternativeText="Upload Files" 
                  title="Upload Files"
                  onclick="{!c.handleShowModal }" disabled="{!v.disabled}"/>

Parent Controller

handleShowModal: function(component, evt, helper) {
...
$A.createComponent("c:fileUploadModal", {relatedRecordId: recordId},
    function(content, status) {
        if (status === "SUCCESS") {
            ...
            var modalPromise = component.find('overlayLib').showCustomModal({
               ...
            });
           component.set("v.modalPromise", modalPromise);
       }                               
    });
},

handleFileUploaded : function(component, event, helper){
    // component.find("overlayLib").notifyClose(); DOES NOT WORK
    component.get('v.modalPromise').then(function (modal){
        modal.close();
    });
}

Event

<aura:event type="APPLICATION">
</aura:event>

Modal Markup

<aura:attribute name="relatedRecordId" type="string"/>
<aura:registerEvent name="fileUploaded" type="c:fileUploaded"/>

<lightning:fileUpload  name="fileUploader"
                   multiple="false"
                   accept="{!v.fileExtensions}"
                   recordId="{!v.relatedRecordId}"
                   onuploadfinished="{!c.handleUploadFinished }"/>

Modal Component

handleUploadFinished: function (component, event) {
    var fireEvent = $A.get("e.c:fileUploaded");
    fireEvent.fire();
}

tl;dr:

  • In the parent component save the promise from launching the modal.
  • From the modal send an APPLICATION event when files are uploaded.
  • In the parent component listen for that event and close the modal using saved promise.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x