Issue with multiple dropdown menus not closing when clicked on

The current implementation provides the functionality to convert select boxes into list items for styling purposes.

However, a drawback of the current setup is that once a dropdown is opened, it can only be closed by clicking on the document or another dropdown menu.

I am seeking recommendations on improving this behavior. The goal is to make sure that clicking on a different dropdown item will toggle off the current one. But if you click on the same item again, it should only activate and not deactivate it.

var jq = jQuery.noConflict();
(function (jq) {

    // Iterate over each select element
    jq('.selectBoxStyle').each(function () {

        // Cache the number of options
        var sthis = jq(this),
            numberOfOptions = jq(this).children('option').length;

        // Hides the select element

        if (jq('html').hasClass('touch')) {

            jq('.options').addClass('s-hidden');

            sthis.wrap('<div class="select"></div>');

            // Insert a styled div to sit over the top of the hidden select element
            sthis.wrap('<div class="styledSelect"></div>');


        } else {

            sthis.addClass('s-hidden');

            // Wrap the select element in a div
            sthis.wrap('<div class="select"></div>');

            // Insert a styled div to sit over the top of the hidden select element
            sthis.after('<div class="styledSelect"></div>');

            // Cache the styled div
            var styledSelect = sthis.next('div.styledSelect');

            // Show the first select option in the styled div
            styledSelect.text(sthis.children('option').eq(0).text());

            // Insert an unordered list after the styled div and also cache the list
            var slist = jq('<ul />', {
                'class': 'options'
            }).insertAfter(styledSelect);

            // Insert a list item into the unordered list for each select option
            for (var i = 0; i < numberOfOptions; i++) {
                jq('<li />', {
                    text: sthis.children('option').eq(i).text(),
                        "data-value": sthis.children('option').eq(i).val(),
                        "class": sthis.children('option').eq(i).attr('class'),
                        "data-sku": sthis.children('option').eq(i).data('sku'),
                        "data-stock": sthis.children('option').eq(i).data('stock')
                }).appendTo(slist);
            }

            // Cache the list items
            var slistItems = slist.children('li');

            // Show the unordered list when the styled div is clicked (also hides it if the div is clicked again)

            styledSelect.click(function (e) {
                e.stopPropagation();
                //jq(this).toggleClass('clickme').removeClass('active');

                jq('div.styledSelect.active').each(function () {
                    jq(this).removeClass('active').next('ul.options').hide();
                    console.log(this);
                });

                jq(this).toggleClass('active').next('ul.options').toggle();


            });

            // Hides the unordered list when a list item is clicked and updates the styled div to show the selected list item
            // Updates the select element to have the value of the equivalent option
            slistItems.click(function (e) {
                e.stopPropagation();
                styledSelect.text(jq(this).text()).removeClass('active');
                jq(this).addClass("selected").siblings().removeClass("selected");
                sthis.val(jq(this).attr('value'));
                slist.hide();
                /* alert($this.val()); Uncomment this for demonstration! */
            });

            // Hides the unordered list when clicking outside of it
            jq(document).click(function () {
                styledSelect.removeClass('active');
                slist.hide();
            });
        }



    });
}(jq));
body {
    background-color:white;
}
.selectSizeMain {
    width: 56.77966%;
    float: none;
    margin: 2.1875rem auto auto;
}
.s-hidden {
    visibility:hidden;
    padding-right:10px;
}
.select {
    cursor:pointer;
    display:inline-block;
    position:relative;
    color:black;
    font-family: GibsonRegular, HelveticaNeue, Helvetica, sans-serif;
    font-size: 14px;
    font-size: .875rem;
    height: 40px;
    width: 100%;
}
.styledSelect {
    position:absolute;
    top:0;
    right:0;
    bottom:0;
    left:0;
    padding: 11px 13px;
    border: 1px solid #ddd;
    background-color: #fff;
}
.styledSelect:after {
    content:"";
    width:0;
    height:0;
    border:5px solid transparent;
    border-color:black transparent transparent transparent;
    position:absolute;
    top: 17px;
    right: 9px;
}
.styledSelect.active:after {
    content:"";
    width:0;
    height:0;
    border:5px solid transparent;
    border-color:green transparent transparent transparent;
    position:absolute;
    top: 17px;
    right: 9px;
}
.options {
    display:none;
    position:absolute;
    max-height: 280px;
    overflow-y:scroll;
    top:100%;
    right:0;
    left:0;
    z-index:999;
    margin:0 0;
    padding:0 0;
    list-style:none;
    border:1px solid #ccc;
    border-top:none;
    background-color:white;
}
.options li {
    padding: 11px 13px;
    margin:0 0;
}
.options li:hover {
    background-color: #000;
    color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

<div class="selectSizeMain">
    <select class="selectBoxStyle">
        <option value="">Choose Size</option>
        <option value="aye">Aye</option>
        <option value="eh">Eh</option>
        <option value="ooh">Ooh</option>
        <option value="whoop">Whoop</option>
    </select>
</div>
<select class="selectBoxStyle">
    <option value="">Month&hellip;</option>
    <option value="january">January</option>
    <option value="february">February</option>
    <option value="march">March</option>
    <option value="april">April</option>
    <option value="may">May</option>
    <option value="june">June</option>
    <option value="july">July</option>
    <option value="august">August</option>
    <option value="september">September</option>
    <option value="october">October</option>
    <option value="november">November</option>
    <option value="december">December</option>
</select>

Answer №1

To achieve this, you can check if the select that was clicked already has the class .active. If it does, you can close all other open selects and then decide whether to use the toggleClass("active") on it.

Your callback function would change from:

styledSelect.click(function (e) {
    e.stopPropagation();

    jq('div.styledSelect.active').each(function () {
        jq(this).removeClass('active').next('ul.options').hide();
        console.log(this);
    });

    jq(this).toggleClass('active').next('ul.options').toggle();
});

to:

styledSelect.click(function (e) {
    e.stopPropagation();
    var closeClicked = jq(this).hasClass("active");

    jq('div.styledSelect.active').each(function () {
        jq(this).removeClass('active').next('ul.options').hide();
        console.log(this);
    });

    if (!closeClicked){
        jq(this).toggleClass('active').next('ul.options').toggle();
    }    
});

You can view a demonstration of this solution in this JSFiddle. It may not be the most elegant approach, but it's effective and only requires a small modification to your existing code. I hope this information is helpful! Feel free to reach out if you have any questions.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is the default animation duration of Compass being ignored?

After recently updating to Compass version 1.0.16, I started setting up basic usage of the new animation features. However, I encountered an issue where setting default values for different animation settings did not take effect. This led me to hard-code t ...

Error in Angular Google Maps Component: Unable to access the 'nativeElement' property as it is undefined

I am currently working on creating an autofill input for AGM. Everything seems to be going smoothly, but I encountered an error when trying to integrate the component (app-agm-input) into my app.component.html: https://i.stack.imgur.com/mDtSA.png Here is ...

Sass Alert: The mixin called roboto-family is missing from the stylesheet. Trace: Problem detected in src/pages/forms/forms.scss at

Greetings, I am diving into the world of Ionic for the first time. Recently, I embarked on a new project in Ionic and decided to integrate a theme. To do so, I copied an .html file, an .scss file, and also created a .ts file. Forms.html <!DOCTYPE html ...

Avoiding line breaks when using an :after pseudo element

I am trying to style external links by adding a pseudo :after element right after the link itself, but I'm having trouble getting it to work on the same line. Here is the CSS code I have: a:not([href*="domain"])::after { content: url(data:image/svg+ ...

What is the difference between the functionality of appendTo and append methods in jQuery?

I'm currently injecting styling into an iframe using a textbox and I find it interesting that appendTo works while append doesn't. I always thought these two methods were essentially the same, with slight performance variances: var contents = $( ...

Issues with CSS Min-Height in Various Web Browsers

Lately, I've been working on a website and trying to create a border that surrounds all my content and extends the full length of the page. The #Container div is supposed to expand to fill the entire page. I've tried using min-height:100%; in my ...

Unbelievable attribute: sup causing peculiar styling in link element

We've recently come across an issue where the text-decoration of an underline in an anchor tag appears strange when there is a sup element present. The visual glitch looks like this: For reference, here's the HTML structure we are working with: ...

Guide on sending a request to an API and displaying the retrieved information within the same Express application

I recently developed a basic express app with API and JWT authentication. I am now attempting to enhance the app by incorporating page rendering through my existing /api/.. routes. However, I am facing challenges in this process. app.use('/', en ...

Retrieving parameters from the URL in Angular

I'm facing an issue with my app. I am currently using a factory to manage data for two controllers. When I click on a link that redirects me to another view with a specific URL, I want to reuse the last tag in the URL by slicing it like this: window. ...

redactor.js: Disable backspace functionality when cursor is at the start of a div-container

Currently, I am working with the redactor.js editor that utilizes editable div containers. A challenge I have encountered is when multiple contenteditable containers are nested; deleting content using the backspace button can inadvertently delete the entir ...

A guide to transferring modules between component files in JavaScript

My query pertains to the handling of imports in web pages. When a file is imported into another, do the declarations and imports from the imported file become available in the file where it is being imported? A suggestion was made for me to import a compo ...

Host app is failing to render shared components in SSR

Encountering an issue while implementing SSR with module federation? Check out my code example Steps to Begin: Run yarn install:all command Execute yarn shell:server:build task Start the server using yarn shell:server:start Initiate remote services with y ...

Styling CSS for Centering a Heading on an Image's Center

Struggling to center an h3 heading in the middle of an image within a grid? Look no further, as I have 3 images across one row - four columns per image/heading. Check out the desired layout https://i.stack.imgur.com/8VFRt.png I've managed to center t ...

Insert elements to an XML document in Node.js using libxmljs

I've been working on updating an XML file by adding a new child node using the code below: var libxml = require('libxmljs'); var xml = '<?xml version="1.0" encoding="UTF-8"?>' + '<root>' + ...

Close button located in the upper-right corner is partially cut off

My challenge involves placing a close button on the top right corner of a #main div that contains an image of varying or larger size. I need the close button to slightly protrude outside the div using negative margins. The issue is that when I use overflow ...

Transforming FormData string key names into a Json Object that is easily accessible

Recently, I encountered an issue where my frontend (JS) was sending a request to my backend (Node Typescript) using FormData, which included images. Here is an example of how the data was being sent: https://i.stack.imgur.com/5uARo.png Upon logging the r ...

"The issue with AngularJS ng-init, preventing the initialization of a variable at

For my project, I have implemented ng-repeat from the AngularJS directive to display an array containing JSON values with subarrays. <div ng-repeat="data in MENULIST" > //MENULIST contains an array of data I then perform certain conditions checks ...

putting a division element above a image carousel

Is there a way to overlay a div tag on top of a slideshow, similar to the one shown in this link? In the example provided, a div with the title "DISCOVER THE JOY OF COOKING" is positioned over a slideshow. Any tips on how I can achieve this effect? ...

Switching Text in ReactJS from V to X: A Tutorial

I have been utilizing a Switch component from react-switch in my project. import Switch from 'react-switch'; render() { return <Switch onChange={this.onChangeStatus} onClick={this.onChangeStatus} c ...

Exploring file writing using Node Webkit and JavaScript

When developing my app, I encountered an issue with the 'fs' module not functioning as expected. Despite the code being written to write a file, nothing happens when the app is launched. However, if I start the app using the following command: $ ...