Pradeep Kumar
Pradeep Kumar

Reputation: 6969

Show/Hide Combobox Dropdown with pure Javascript

I have a user control in asp.net that outputs markup similar to the following:

<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>

A javascript file accompanying this control has the following class (minimal code to reproduce the problem only):

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';
      //-- some more custom handling code follows here --
    }
  };
  pnlComboBox.onclick = function() {
    isCollapsed = !isCollapsed;
    pnlDropdownList.style.display = (isCollapsed) ? 'none' : 'block';
  };
  pnlContainer.onclick = function(event) {
    event.stopPropagation();
  };
  document.addEventListener('click', function() {
    collapseDropdown();
  }, false);
}

And finally, on my page I create an instance of the class like this:

cb1 = new ComboBox('combobox1');

All this works fine until there is only one instance of this control. It collapses correctly whenever anything or anywhere outside the control is clicked, just as expected.

The Problem:

The problem happens when there are more than one instances of this control on the page. If one of the comboboxes is open, and user clicks on another instance of my combobox, the previous one doesn't collapse.

JsFiddle for minimal code to reproduce the problem can be found here:

https://jsfiddle.net/x8qjo79f/

I know it is happening because of event.stopPropagation() call, but don't know what to do for this.

Upvotes: 2

Views: 563

Answers (2)

le_m
le_m

Reputation: 20228

Edit the document onclick event listener to capture the event (so it is executed before the bubbling phase) and collapse when its target is outside your 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';
      //-- some more custom handling code follows here --
    }
  };
  pnlComboBox.onclick = function() {
    isCollapsed = !isCollapsed;
    pnlDropdownList.style.display = (isCollapsed) ? 'none' : 'block';
  };
  pnlContainer.onclick = function(event) {
    event.stopPropagation();
  };

  // Edit: 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>

Upvotes: 2

Martin Parenteau
Martin Parenteau

Reputation: 73731

You could allow the event propagation in pnlContainer.onclick but remember that the ComboBox was clicked. Inside the document click event handler, you would test if the ComboBox is the clicked one, and allow to collapse only if it is not.

The changes to the Javascript code could look like this:

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

Upvotes: 2

Related Questions