1

I'm trying to do the popover shown on the lightning tutorial: https://www.lightningdesignsystem.com/components/popovers/

I'm new to lightning and I have been looking around on how to hide the popover when a user clicks outside of it but I haven't had much success. Most of the other solutions use jQuery and I don't want to use it. I tried following this solution: How to Close SLDS Dropdown Menu when clicked outside in Lightning Component?

But it doesn't seem to work or I don't know how to apply it properly.

Here is the component and it is embedded into a lightning application that has nothing else but this component:

<aura:component>
<ltng:require styles="{!$Resource.slds214 + '/assets/styles/lightning-design-system-ltng.css'}" />
<span class="star-rating">
    <ui:inputRadio name="stars" text="1" change="{!c.getRating}" /><i></i>
    <ui:inputRadio name="stars" text="2" change="{!c.getRating}" /><i></i>
    <ui:inputRadio name="stars" text="3" change="{!c.getRating}" /><i></i>
    <ui:inputRadio name="stars" text="4" change="{!c.getRating}" /><i></i>
    <ui:inputRadio name="stars" text="5" change="{!c.getRating}" /><i></i>
</span>
<p>Here's some text omg.</p>
The value of your selection is: <ui:outputText class="result" aura:id="rating" value=""></ui:outputText>

<div aura:id="submissionPopover" class="slds-popover slds-nubbin--left-bottom slds-hide" role="dialog" onblur="{!c.hidePopover}">
  <div class="slds-popover__body" >
    <p> lot's of stuff ... </p>
  </div>
</div>

Here is the controller:

({
 getRating : function(cmp, evt) {
    /* previous logic... */
    var myPopover = cmp.find('submissionPopover');
    $A.util.removeClass(myPopover, 'slds-hide');
},

hidePopover : function(cmp, evt) {
    var myPopover = cmp.find('submissionPopover');
    $A.util.toggleClass(myPopover, 'slds-hide');
}
})

It seems that the onBlur event in the div is not firing but the change in the inputRadio is.

Is there a solution to how I can get the popover to disappear? Thanks!

2 Answers 2

3

The simplest way I can think of is to set the focus on your popup, then create a method to close the popup when focus is lost. One important thing to note is that writing to the dom is slow, so you need to provide a delay before assigning focus. Here the target is a text input, you will have to update to an appropriate target to focus on within your un-hidden div.

app.cmp

<div aura:id="submissionPopover" class="slds-hide">
  <textarea aura:id="comment" class="slds-textarea" onblur="{!c.hidePopover}" />
</div>

controller.js

({
    getRating : function(cmp, evt, helper) {
      /* previous logic... */
      var myPopover = cmp.find('submissionPopover');
      $A.util.removeClass(myPopover, 'slds-hide');
      setTimeout(function(){helper.setFocus(cmp)}, 300);
    },

    hidePopover : function(cmp, evt) {
        var myPopover = cmp.find('submissionPopover');
        $A.util.toggleClass(myPopover, 'slds-hide');
    }
)}

helper.js

({
    setFocus : function(cmp) {
        cmp.find("comment").getElement().focus();
    }
})

Hope that helps!

1
  • This works really well! The only downside of this solution is that when I have the user click on star ratings and when they reselect a solution, the popover disappears and reappears.
    – akcorp2003
    Nov 14, 2016 at 15:43
2

Events like onblur,onfocus..few other events works well for input elements(i.e input,select,textarea) but not for element that displays text contents div,p,span..etc

You can fire an onblur event on a div by adding tab-index but it won't work in LC because the attribute is being striped off after DOM is rendered.

One way I did in my projects, is to register click event in the window. So, when a click happens I'll check if it happened,

  1. inside of the popover div - Do Nothing
  2. outside of the popover div - Remove the click event from window and hide the div.

This how your getRating would look like after adding above logic:

getRating : function(cmp, evt) {
    /* previous logic... */
    var myPopover = cmp.find('submissionPopover');
    $A.util.removeClass(myPopover, 'slds-hide');

    var clickedFn;

    clickedFn = $A.getCallback(function(event){
        //Add setTimeout() if you need to hide with a delay

        var popoverEle = myPopover.getElement();
        //if click happened outside of popover div hide
        if(!popoverEle.contains(event.target)){
            $A.util.toggleClass(myPopover, 'slds-hide');
            window.removeEventListener('click',clickedFn);
        }
    });

    window.addEventListener('click',clickedFn);
},
3
  • Thanks for the response! I guess I didn't say that inside the popover, the user enters some text (i.e. there's a text area inside). So with this logic, when the user clicks inside the text area, the popover disappears. Any reason that would happen?
    – akcorp2003
    Nov 14, 2016 at 15:38
  • @akcorp2003 You should have added info about the textarea within the popover.I have updated the answer check it out.
    – Praveen
    Nov 15, 2016 at 4:22
  • Sorry about that... :( I tried your code out but it's always hiding the popover. It seems like the condition is always true and it's showing the popover and then immediately hiding it.
    – akcorp2003
    Nov 15, 2016 at 15:32

You must log in to answer this question.

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