2

Just having a couple of issues, with the below script I've made.

It works perfectly in terms of toggling the form panels, however when i then start to interact with the 'Active' panel (ie click a input field), the active class is removed from its parent element, thus minimizing the panel.

$(function () {
    $('.options-list li').click(function () {
        $(this).toggleClass('active');
        $(this).parent().children('li').not(this).removeClass('active');
    });
});

Is there a way I can restrict the toggle function to only the title contents?

https://jsfiddle.net/os883y47/

I think its due to the 'Title' within the <'li'> not having its own containing element, so I wrapped the text within a <'span'> element & this appears to fix the form minimising issue however now the 'active' class isn't getting removed (assuming its now a child selector issue??).

https://jsfiddle.net/avk7e30a/

Any help would be greatly appreciated.

Tushar
  • 85,780
  • 21
  • 159
  • 179
raym01
  • 73
  • 7

5 Answers5

2

This is happening because of event bubbling to the li. The click events on the input are bubbled up to the li element and the event handler is executed again. To stop this from happening, use event.stopPropagation() on child elements event handlers.

Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.

Updated Fiddle

Add following code

$('.active-panel').click(function (e) {
    e.stopPropagation(); // Stop event from bubbling up
});

$(function() {
  $('.options-list li').click(function() {
    $(this).toggleClass('active');
    $(this).parent().children('li').not(this).removeClass('active');
  });

  $('.active-panel').click(function(e) {
    e.stopPropagation();
  });
});
.options-list {
  border: 1px solid #d5d6d7;
  padding: 0;
  margin-bottom: 30px;
}
.option {
  list-style: none;
  border-bottom: 1px solid #dadada;
  font: 16px/56px avenir_65regular !important;
  color: #333;
}
.options-list .option.active {
  color: #004ebc;
}
.options-list .option.active:before {
  background-color: #004ebc !important;
  border: 5px solid #83ace0 !important;
}
.options-list .option:before {
  content: "";
  background-color: #fff;
  border-radius: 16px;
  border: 5px solid #004ebc;
  height: 18px;
  margin: 0 10px;
  width: 18px;
  position: relative;
  top: 3px;
  box-sizing: border-box;
  display: inline-block;
}
.panel {
  height: 0;
  overflow: hidden;
  background: #f9f9f9;
  border-top: 1px solid #d5d6d7;
  transition: all 0.5s linear;
  transition: height 0.25s ease-in-out;
  /* visibility: hidden; */
  /* opacity: 0; */
  /* transition: visibility 0s, opacity 0.5s linear; */
}
.option.active > .panel {
  /* visibility: visible; */
  /* opacity: 1; */
  height: 100%;
  padding: 25px 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul class="options-list">
  <li class="option active">FORM FIELD 1
    <div class="panel active-panel">
      <div class="form-field">
        <label class="form-label black">Sub Field</label>
        <input class="form-input" type="text" />
      </div>
      <div class="form-field flt">
        <label class="form-label black">Sub Field</label>
        <input class="form-input half" type="text" />
        <input class="form-input half" type="text" />
      </div>
      <div class="form-field flt">
        <label class="form-label black cvc">Sub Field</label>
        <input class="form-input half" type="text" />
      </div>
    </div>
  </li>
  <li class="option">FORM FIELD 2
    <div class="panel"></div>
  </li>
  <li class="option">FORM FIELD 3
    <div class="panel"></div>
  </li>
</ul>

Read: What is event bubbling and capturing?

Community
  • 1
  • 1
Tushar
  • 85,780
  • 21
  • 159
  • 179
0

HTML is the same.

JQuery

$(function() {
    $('.options-list li').click(function(){
        $(this).closest('.options-list').find('.active').removeClass('active');
        $(this).addClass('active');
    });
});

Here is a fiddle : https://jsfiddle.net/os883y47/2/

Arpp
  • 301
  • 1
  • 11
0

I would add the following code as the first statements in your handler, so it only continues if the click was on a direct child (li) of the .options-list element:

$('.options-list li').click(function(e){
    if (!$(e.target).parent().is('.options-list')) {
        return;
    }
    ...

Here is the fiddle.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • This is something you hard-code to a specific element. If the element changes in future and the class remains the same, it functions wrong – Shankar Us Nov 21 '15 at 09:16
  • Yes, but the handler itself is already on `li` in the original code. But I have altered the code to check for the parent class. – trincot Nov 21 '15 at 09:18
  • True but if it has a child `li`, and a click event is triggeres on it, then it goes wrong – Shankar Us Nov 21 '15 at 09:22
  • That's another thing. I have just updated the code to check for the parent class. Of course, if they get nested, it will not work. – trincot Nov 21 '15 at 09:24
0

Change your code to following

$(function() {
    $('.options-list li').click(function(e){
        if (e.target === this) {
           $(this).toggleClass('active');
           $(this).parent().children('li').not(this).removeClass('active');
        }
    });
}); 

This is because, you added click event to the parent, so even when you click its children the event get triggered. So a validation is required to confirm it is parent element

Shankar Us
  • 292
  • 1
  • 3
  • 18
0

You may want to prevent the click-event on the panels:

JavaScript

$('.options-list li .panel').click(function(evt){
    evt.preventDefault();
    return false;
});

JSFiddle

Arg0n
  • 8,283
  • 2
  • 21
  • 38