Display/Conceal Dropdown Menu for Combobox Using only Javascript

In my asp.net user control, I am generating markup that looks like this:

<div id="combobox1">
  <div id="combobox1_text"><span>combobox 1</span></div>
  <div id="combobox1_ddl">
    <input type="checkbox" id="combobox1_$1" />
    <label for="combobox1_$1">Item 1</label>
    <br />
    <input type="checkbox" id="combobox1_$2" />
    <label for="combobox1_$2">Item 2</label>
    <br />
    <input type="checkbox" id="combobox1_$3" />
    <label for="combobox1_$3">Item 3</label>
    <br />
    <input type="checkbox" id="combobox1_$4" />
    <label for="combobox1_$4">Item 4</label>
    <br />
    <input type="checkbox" id="combobox1_$5" />
    <label for="combobox1_$5">Item 5</label>
    <br />
  </div>
</div>

Accompanying this control is a javascript file with the following class (simplified code):

ComboBox = function(cb) {
  var pnlContainer = document.getElementById(cb);
  var pnlComboBox = document.getElementById(cb + '_text');
  var pnlDropdownList = document.getElementById(cb + '_ddl');
  var isCollapsed = true;

  var collapseDropdown = function() {
    if (!isCollapsed) {
      isCollapsed = true;
      pnlDropdownList.style.display = 'none';
      //-- additional custom handling code --
    }
  };
  pnlComboBox.onclick = function() {
    isCollapsed = !isCollapsed;
    pnlDropdownList.style.display = (isCollapsed) ? 'none' : 'block';
  };
  pnlContainer.onclick = function(event) {
    event.stopPropagation();
  };
  document.addEventListener('click', function() {
    collapseDropdown();
  }, false);
}

To create an instance of this class on my page, I use the following code:

cb1 = new ComboBox('combobox1');

Everything works perfectly until there are multiple instances of this control on the page. When one combobox is open and the user clicks on another combobox, the previous one doesn't collapse.

The Issue:

The problem arises from the event.stopPropagation() call, but resolving it is unclear to me.

For further details and demonstration, refer to the JsFiddle link below:

https://jsfiddle.net/x8qjo79f/

I recognize that the issue stems from event.stopPropagation(), however, I'm uncertain about how to address it.

Answer №1

Modify the document's onclick event listener to capture the event before the bubbling phase and collapse when its target is outside the specified combobox.

ComboBox = function(cb) {
  var pnlContainer = document.getElementById(cb);
  var pnlComboBox = document.getElementById(cb + '_text');
  var pnlDropdownList = document.getElementById(cb + '_ddl');
  var isCollapsed = true;

  var collapseDropdown = function() {
    if (!isCollapsed) {
      isCollapsed = true;
      pnlDropdownList.style.display = 'none';
      //-- additional custom handling code goes here --
    }
  };
  pnlComboBox.onclick = function() {
    isCollapsed = !isCollapsed;
    pnlDropdownList.style.display = (isCollapsed) ? 'none' : 'block';
  };
  pnlContainer.onclick = function(event) {
    event.stopPropagation();
  };

  // Update: Capture click event
  document.addEventListener('click', function(event) {
    if (!pnlContainer.contains(event.target)) collapseDropdown();
  }, true);
}

cb1 = new ComboBox('combobox1');
cb2 = new ComboBox('combobox2');
#combobox1,
#combobox2 {
  border: 1px solid black;
  cursor: default;
  width: 200px;
  font-family: verdana;
  font-size: 10pt;
}

#combobox1_text,
#combobox2_text {
  padding: 2px;
}

#combobox1_ddl,
#combobox2_ddl {
  border-top: 1px solid black;
  display: none;
}
<div id="combobox1">
  <div id="combobox1_text"><span>combobox 1</span></div>
  <div id="combobox1_ddl">
    <input type="checkbox" id="combobox1_$1" />
    <label for="combobox1_$1">Item 1</label>
    <br />
    <input type="checkbox" id="combobox1_$2" />
    <label for="combobox1_$2">Item 2</label>
    <br />
    <input type="checkbox" id="combobox1_$3" />
    <label for="combobox1_$3">Item 3</label>
    <br />
    <input type="checkbox" id="combobox1_$4" />
    <label for="combobox1_$4">Item 4</label>
    <br />
    <input type="checkbox" id="combobox1_$5" />
    <label for="combobox1_$5">Item 5</label>
    <br />
  </div>
</div>
<br />
<input type="text" />
<br />
<input type="button" />
<br />
<input type="checkbox" />
<br />
<span>some random text in the document.. <br />blah. blah.. blah..</span>
<br />
<br />
<br />
<div id="combobox2">
  <div id="combobox2_text"><span>combobox 2</span></div>
  <div id="combobox2_ddl">
    <input type="checkbox" id="combobox2_$1" />
    <label for="combobox2_$1">Item 1</label>
    <br />
    <input type="checkbox" id="combobox2_$2" />
    <label for="combobox2_$2">Item 2</label>
    <br />
    <input type="checkbox" id="combobox2_$3" />
    <label for="combobox2_$3">Item 3</label>
    <br />
    <input type="checkbox" id="combobox2_$4" />
    <label for="combobox2_$4">Item 4</label>
    <br />
    <input type="checkbox" id="combobox2_$5" />
    <label for="combobox2_$5">Item 5</label>
    <br />
  </div>
</div>

Answer №2

If you want to allow event propagation in pnlContainer.onclick, just keep in mind that the ComboBox was the element that triggered the click. In the document's click event handler, you can check if the ComboBox was clicked and only collapse it if it wasn't.

To implement this behavior, make these changes to your JavaScript code:

ComboBox = function(cb) {
  var isClicked = false;
  ...
  pnlContainer.onclick = function(event) {
    isClicked = true;
  };
  document.addEventListener('click', function() {
    if (isClicked) {
      isClicked = false;
    }
    else {
      collapseDropdown();
    }
  }, false);
}

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

Modifying CSS using jQuery in a PHP While Loop

I've been racking my brain trying to solve this issue, experimenting with different approaches but so far, no luck. Question: How can I dynamically change the color of a specific div within a PHP while loop using jQuery after receiving an AJAX respon ...

Magical Stylist - Eradicate Indicators while Preserving Labeling

Recently, I've been experimenting with the Google styling wizard in an effort to remove markers while retaining labels for businesses. My objective is to eliminate the marker icons but still display the text labels such as "Jimmy Johns," "Boone Saloon ...

Successful Ajax response notification

I am new to using ajax and I want to implement a .post method with an if condition to notify the user of its success or failure. Here is my code for .post: $.post("ajaxRegistering.php",{ name: name, lastname: lastname, ...

toggle switch for numerical input

Whenever the "Qty" radio button is selected, I need to activate an input box that accepts numbers. Conversely, when the "rate" radio button is clicked, I want to disable this input box. This is how I designed it: <input type="radio" class="radioBtn" ...

Use AJAX to send a form submission along with an anchor tag

I've been facing a challenge trying to make this work, but unfortunately, I haven't had any success. Typically, all my forms include a submit input, and I handle AJAX submission in the following manner: <script> $("input#submit").click(fun ...

Error code E11000 is thrown due to a duplicate key in a Node.js application

Whenever I input data on the webpage, it syncs correctly with the database. However, when I attempt to fill out the same form again, an error occurs: { "code": 11000, "index": 0, "errmsg": "E11000 duplicate key error collection: test.creates i ...

The value attribute in the HTML input tag being dynamically increased by JavaScript

Hi there, can someone help me figure out how to save changes to the value attribute of an HTML input tag that is being incremented by JavaScript? Currently, every time I click on a specific element, the input field should increase by one. The problem is th ...

What is the process for arranging multiple text boxes beside a radio button upon selection?

Displayed below is the HTML code for a page featuring three radio buttons- <html> <body> <form> <input type="radio" name="tt1" value="Insert" /> Insert<br /> <input type="radio" name="tt2" value="Update" /> Update<b ...

Using the directive in AngularJS and passing ng-model as an argument

Currently, I am creating a custom directive using AngularJs, and my goal is to pass the ng-model as an argument. <div class="col-md-7"><time-picker></time-picker></div> The directive code looks like this: app.directive(' ...

Dynamic form validation using jQuery

I am facing a challenge with validating a dynamic form on the user side. My goal is to ensure that if a user fills out one column in a row, they are required to fill out the remaining columns as well. For example, filling out the CC # should prompt the use ...

When using jQuery to enable contenthover on divs, they will now start a new line instead of

I've been working on achieving a layout similar to this, with the contenthover script in action: Mockup Draft Of Desired Look However, the result I'm getting is different from what I expected, it can be seen here. The images are not aligning co ...

Ensure the calling object is retained during the resolution of an Angular promise

Identifying the Issue One issue arises when resolving promises in Javascript: the context switches to Window #. This means that referring back to the object resolving the promise becomes tricky because I can't access or modify its variables. The com ...

Implementing the SendOwl License API for theme licensing

Currently developing a Shopify theme for sale and exploring licensing options Considering using SendOwl's API for licenses - Shopify themes support html/css/js/liquid, no server-side code, so JavaScript is required. Can the SendOwl API be used to v ...

Using the built-in http module in node.js to upload images via multipart/form-data

I have encountered an issue where I need to send two images and an API key as part of a multipart/form-data HTTP request to an API. The images are retrieved from an AWS S3 bucket, which works fine. However, when attempting to send the image data as part ...

Angular.js: The Best Way to Attach a "Change" Event to a Service

Just starting out with angular.js... I have a HTML5 page where I can input new URLs along with names. Now, I need to validate these URLs against a back-end service to see if they already exist. How can I trigger the “onChange” event on the input field ...

Challenges of N-tier architecture integration with WCF and ASP.NET session management

While working on a personal project, I encountered an issue related to the n-tier architecture being used: Framework. WCF Framework service. ASP.NET control that connects to the WCF Framework services on the server-side. ASP.NET client hosting that contr ...

Location-based services: Updating the position of a Google Maps marker without refreshing the entire map interface

How can I update only the marker on a map when the device is in motion or has increased accuracy? I want to reload the map when the position changes, but only move the marker. Below is the code snippet that I currently have: if (navigator.geolocation) { ...

VueJS failing to pass parent data to child component

I'm fairly new to Vue Framework and I'm trying to figure out how to update a child component based on changes in the parent component's attributes. In the code snippet below, I've created a component that displays a greeting message bas ...

Determining the percentage of a bar in d3.js when hovering over it

I am working with a d3 chart and looking to implement a tooltip feature that displays the label of the bar section along with the percentage it represents in relation to the total bar. Initially, I considered calculating the height of the hovered section t ...