2

I am using SLDS Picklist in Aura Component, I am trying to close the picklist when user clicked outside the picklist. I am trying to bind a click event to document and call the action to close the picklist. To achieve this I am calling

document.addEventListener("click",function(){
                $A.util.toggleClass(picklist,'slds-is-open');
            });

I am doing this when the user clicks on the picklist, but When I click on the picklist it is setting the click event on document, it is being fired on the same click and closes the picklist. Is there a better way to achieve this functionality?.

  • addEventListener click is being executed before it is intended to execute. I think the problem is here. Not yet able to figure out why it is being called prior – Vijay Nov 11 '16 at 21:09
0

Check this out: https://stackoverflow.com/questions/152975/how-do-i-detect-a-click-outside-an-element.

You need to add a separate event to your actual picklist element to prevent the event from bubbling up to the document and triggering the handler.

| improve this answer | |
0

You can see implementation of strike components. https://github.com/appiphony/Strike-Components/blob/master/aura/strike_multiSelectPicklist/strike_multiSelectPicklistController.js

What they have done is

component.closeMenu = $A.getCallback(function() {
            if (component.isValid()) {
                $A.util.toggleClass(picklist,'slds-is-open');

            } else {
                window.removeEventListener('click', component.closeMenu);
            }
        });

        window.addEventListener('click', component.closeMenu);

I think $A.getCallback(function() {}) is missing in your implementation. And also function reference is stored on component(component.closeMenu) itself. (You can store any value in component just by using component. = 'value'. you can use this value afterwards. This is not recommended way to store any value)

Another way to do so is by using a hidden div.

<div>
   <your HTMl for dropdown>
   <div class="hiddenDiv" onclick="{!c.hidePopover}"/>
<div>

and in your css

.THIS .hiddenDiv{
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    z-index: 1;
    position: fixed;
}

now in hidePopover action you have to add slds-hide class to hiddenDiv and hide dropdown also

| improve this answer | |
0

Things have changed over the years, but because this question was bumped to homepage:

Today you can just use lightnig:select

<lightning:select aura:id="select" name="select1" label="How many tickets?" required="true">
    <option value="">choose one...</option>
    <option value="1">one</option>
    <option value="2">two</option>
    <option value="3">three</option>
</lightning:select>

Auto close of picklist after loosing focus is of course already handled :) To focus on that picklist again you can use focus() method.

Full example with controller:

<aura:component>
    <lightning:select aura:id="select" name="select1" label="How many tickets?" required="true">
        <option value="">choose one...</option>
        <option value="1">one</option>
        <option value="2">two</option>
        <option value="3">three</option>
    </lightning:select>
    <lightning:button variant="base" label="Base" title="Base action" onclick="{! c.handleClick }"/>
</aura:component>

Controller:

    handleClick : function(component, event, helper){
       component.find("select").focus();
   }
| improve this answer | |
0

Just to add another voice to this. I recently had a requirement to make a custom dropdown that included a checkbox group as its content instead of a single select list.

The way I eventually achieved the 'click away to close' behaviour ended up being far simpler than I at first thought. For one thing, I completely avoided adding click handlers to the window, as I just could not get that to work!

Here's what I did:

I added a clickable div that I called the 'Drop Down Mask' just above the button that opens the dropdown.

<!-- clickable mask -->
<div aura:id="dropdownMask" id="dropdownMask" class="slds-hide" onclick="{!c.toggleDropdown}"></div>

<!-- dropdown container -->
<div class="dropdown">

        <!-- the button that triggers the dropdown -->
        <div onclick="{!c.toggleDropdown}" class="dropbtn">
            {!v.dropdDownButtonLabel}
            <lightning:icon class="downArrow" iconName="utility:down" size="x-small" />
        </div>

        <!-- the dropdown content -->
        <div aura:id="dropdown-content" class="dropdown-content slds-hide">
            <lightning:checkboxGroup name="options checkboxes"
                                     options="{! v.options}"
                                     value="{! v.chosenValues}"
                                     onchange="{! c.handleChange }"/>
        </div>
    </div>

In the controller I had a simple function that handles clicking either the button or the mask by showing or hiding the divs:

toggleDropdown : function(component, event, helper) {
    $A.util.toggleClass(component.find('dropdown-content'), 'slds-hide');
    $A.util.toggleClass(component.find('dropdownMask'), 'slds-hide');
}

...and in the css I made sure that:

  1. The mask covered the entire screen
  2. The mask 'displayed' (although invisible) above the the rest of the component
  3. The entire dropdown container displayed above the mask.
  4. Both classes that have z-index applied have their position set. Otherwise the z-index won't work.
.THIS.dropdownMask {
    content: '';
    width: 100%;
    height: 100vh;
    position: absolute;
    left: 0px;
    top: 0px;
    z-index: 1;
}

/* The container  - needed to position the dropdown content */
.THIS.dropdown {
    position: relative;
    width: 320px;
    margin: auto;
    z-index: 2;
}

Below, for funzies I've left all the css I used, just so anyone that's reading and needs a quick solution can copy/paste and then tweak. This also includes a custom scroll bar on the dropdown content.

/* ~~~~~~~~~~~ \/ drop down styling below this line \/ ~~~~~~~~~~~ */
.THIS#dropdownMask {
    content: '';
    width: 100%;
    height: 100vh;
    position: absolute;
    left: 0px;
    top: 0px;
    z-index: 1;
}

/* The container <div> - needed to position the dropdown content
NOTE: My div sat at component level. If you want to put it inside a another element, you'll need to add a space. example: .THIS .dropdown
 */
.THIS.dropdown {
    position: relative;
    width: 320px;
    margin: auto;
    z-index: 2;
}

.THIS .dropbtn {
    position: relative;
    display: flex;
    align-items: center;
    width: 318.87px;
    height: 34px;
    padding: 0px 1rem;
    background: white;
    border: 1px solid #000000;
    box-sizing: border-box;
    border-radius: 5px;
    cursor: pointer;
}

.THIS .dropbtn .downArrow {
    position: absolute;
    right: 1rem;
}

/* Dropdown button on hover & focus */
.THIS .dropbtn:hover, .THIS .dropbtn:focus {
    background-color: #f7f7f7;
}

/* Dropdown Content (Hidden by Default) */
.THIS .dropdown-content {
    position: absolute;
    background-color: white;
    max-height: 250px;
    width: inherit;
    border-radius: 5px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    overflow: auto;
}

/* checkboxes inside the dropdown */
.THIS .dropdown-content .slds-checkbox {
    color: black;
    padding: 12px 16px;
    text-decoration: none;
}

/* Change color of dropdown links on hover */
.THIS .dropdown-content a:hover {background-color: #ddd}

/* ~~~~~~~~~~~ \/ scroll bar styling below this line \/ ~~~~~~~~~~~ */
/* Scroll Bar width */
.THIS .dropdown-content::-webkit-scrollbar {
  width: 10px;
}

/* Scroll Bar Track */
.THIS .dropdown-content::-webkit-scrollbar-track {
  box-shadow: inset 0 0 5px grey; 
  border-radius: 10px;
}
 
/* Scroll Bar Handle */
.THIS .dropdown-content::-webkit-scrollbar-thumb {
  background: gray; 
  border-radius: 10px;
}

/* Scroll Bar Handle on hover */
.THIS .dropdown-content::-webkit-scrollbar-thumb:hover {
  background: #bababa;
}
/* ~~~~~~~~~~~ /\ drop down styling above this line /\ ~~~~~~~~~~~ */
/* ~~~~~~~~~~~ /\ scroll bar styling above this line /\ ~~~~~~~~~~~ */
enter code here
| improve this answer | |

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.