0

I have a button, which when clicked I want to display two additional buttons Cancel and Confirm.

When o class is added a negative margin left is added and the button disappears.

$('.a_bttn_inner_action').click(function() {
  if ($(this).children().find('.button')) {

    $(this).parent().find('.button').queue(function(next) {
      $(this).addClass('o');
      next();
    });

    $(this).parent().find('.confirm.yes').delay(300).queue(function(next) {
      $(this).removeClass('o');
      next();
    });
    $(this).parent().find('.confirm.no').delay(100).queue(function(next) {
      $(this).removeClass('o');
      next();
    });

  } else if ($(this).children().find('.confirm.no')) {

    $(this).parent().find('.confirm.yes').delay(300).queue(function(next) {
      $(this).addClass('o');
      next();
    });
    $(this).parent().find('.confirm.no').delay(100).queue(function(next) {
      $(this).addClass('o');
      next();
    });

    $(this).parent().find('.button').queue(function(next) {
      $(this).removeClass('o');
      next();
    });
  }
});
li.o {
  margin-left: -800px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="bttn_inner_action">
  <ul class="action">
    <a href="#" class="a_bttn_inner_action">
      <li class="button ">Do something...</li>
    </a>
    <a href="#" class="a_bttn_inner_action">
      <li class="confirm no o">Cancel!</li>
    </a>
    <a href="#" class="a_bttn_inner_action">
      <li class="confirm yes o">Confirm...</li>
    </a>

  </ul>
</div>

With the jQuery I have a problem here if($(this).children().find('.button')) and here else if($(this).children().find('.confirm.no')).

I want to detect which of the current element's children were selected by the class of the li element.

Is this possible?


I've tried if($(this).children().attr('class') == 'button') also doesn't work.

Nikk
  • 7,384
  • 8
  • 44
  • 90
  • Note that your html syntax is invalid, LI are supposed to be direct children of UL. While the various browsers might allow it now, and/or do error correcting to fix it at runtime it could lead to problems later on. For instance during error correction browsers sometimes change the elements and thus they could be in a hierarchy you weren't expecting. – Patrick Evans Aug 23 '18 at 09:08

5 Answers5

3

I believe this is what you are looking after. For checking children you can use

.find('.button').length

it will give back 0 or a positive integer so you can use it inside an if. In your code the first if was always true, so the other would never run.

$('.a_bttn_inner_action').click(function() {

  if ($(this).find('.button').length) {
    $(this).parent().find('.button').queue(function(next) {
      $(this).addClass('o');
      next();
    });

    $(this).parent().find('.confirm.yes').delay(300).queue(function(next) {
      $(this).removeClass('o');
      next();
    });
    $(this).parent().find('.confirm.no').delay(100).queue(function(next) {
      $(this).removeClass('o');
      next();
    });

  } else if ($(this).find('.confirm.no').length) {

    $(this).parent().find('.confirm.yes').delay(300).queue(function(next) {
      $(this).addClass('o');
      next();
    });
    $(this).parent().find('.confirm.no').delay(100).queue(function(next) {
      $(this).addClass('o');
      next();
    });

    $(this).parent().find('.button').queue(function(next) {
      $(this).removeClass('o');
      next();
    });
  }
});
li.o {
  margin-left: -800px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="">
  <ul class="action">
    <a href="#" class="a_bttn_inner_action only-here">
      <li class="button ">Do something...</li>
    </a>
    <a href="#" class="a_bttn_inner_action">
      <li class="confirm no o">Cancel!</li>
    </a>
    <a href="#" class="a_bttn_inner_action">
      <li class="confirm yes o">Confirm...</li>
    </a>

  </ul>
</div>
1

To simply know which button is clicked, you can use the target property of the click event to get the html element clicked =>

$('.elements').on('click', function(e){
     var $targer = $(e.target);
});

You can use the hasClass() jQuery method on a jQuery element, or the is() method, to test the properties of an jQuery/html element.

I rewrite your code snippet keeping the logic, but changing some html. Look at the tests of the clicked element (target).

Your html is malformed, because children of a list ul must be an li element. So your html should be something like this :

<div class="bttn_inner_action">
  <ul class="action">
    <li class="a_bttn_inner_action">
      <a href="#" class="button ">Do something...</a>
    </li>
    <li class="a_bttn_inner_action">
      <a href="#"class="confirm no o">Cancel!</a>
    </li>
    <li class="a_bttn_inner_action">
      <a href="#" class="confirm yes o">Confirm...</a>
    </li>
  </ul>
</div>

$('.button').click(function(e) {
  var $target = $(e.target);
  
  if ($target.hasClass('do-something')) {
    $('.button.confirm.yes').delay(300).queue(function(next) {
      $(this).parent('li').removeClass('o');
      next();
    });
    $('.button.confirm.no').delay(100).queue(function(next) {
      $(this).parent('li').removeClass('o');
      next();
    });
    
  } else if ($target.is('.confirm.no')) {
    $('.button.confirm.yes').delay(300).queue(function(next) {
      $(this).parent('li').addClass('o');
      next();
    });
    $('.button.confirm.no').delay(100).queue(function(next) {
      $(this).parent('li').addClass('o');
      next();
    });
  }
  
});
li.o {
  margin-left: -800px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="bttn_inner_action">
  <ul class="action">
    <li class="li_bttn_inner_action">
      <a href="#" class="button do-something">Do something...</a>
    </li>
    <li class="li_bttn_inner_action o">
      <a href="#"class="button confirm no">Cancel!</a>
    </li>
    <li class="li_bttn_inner_action o">
      <a href="#" class="button confirm yes">Confirm...</a>
    </li>
  </ul>
</div>

The event listener can be optiomized. With $('.class').click() function, listener is attached to each .class elements. Use $('parentElement').on('click', 'subElement', function(e){...}) instead to attach just one event listener to a parent element.

See .on() function on jQuery doc.

roundge
  • 66
  • 9
0

You could just check the count of children with button class.

if ($(this).find('.button').length > 0) {
    // there are some
}
kgbph
  • 841
  • 1
  • 8
  • 26
0

children() gets all the direct child elements of the selected elements. find() gets all the child elements all the way down the hierarchy.

So $(this).children() is going to select all the <li> elements, and then find() is going to look through all of the child elements of those <li> and not at the <li> itself

What you want is just

$(this).find('.button').length 
//or
$(this).find('.confirm.no').length

//or you could just find the li itself and then test for the class
var button = $(this).find('li');
if(button.is('.button')){

} else if(button.is(".confirm.no")){

}

Also note do not test against the return of children() or find() as both will return a new jQuery object wither or not anything was actually found, so the result will always test as truthy.

You could also just put the click handler on the LI themselves and not worry about the invalid wrapping them in an anchor tag

$('ul.action li').click(function() {
  var $this = $(this);
  if($this.is('.button')){

  } else if($this.is('.confirm.no')){

  }
});
Patrick Evans
  • 41,991
  • 6
  • 74
  • 87
0

The answer is the exists() function.


The following statement:

$(this).children().find('.button')

returns a JQuery object whose length is zero even there is no element selected.

So, if ($(this).children().find('.button')) is always going to be passed.

Either you can check the length of the return object or use JQuery exists() function.

Details are here.

Charlie
  • 22,886
  • 11
  • 59
  • 90