slideToggle going crazy, how to target specific element from the class

slideToggle going crazy, how to target specific element from the class
0

#1

I tried to search the Internet for the solution, but haven’t found anything helpful.

I’m building a TwitchTV app and want to make something like that: if the status is online (.online), I can click on it and a panel (.slide) with streaming info will slide down, then up if I click again.

To clarify: I have a few elements with the same class but want to target only the sibling of the one I click.

The problem is, slideToggle goes up and down a few times, and I don’t really know why. I can only guess it has something to do with the order of elements: for example, when the div with online class is the 8th from the end, slide panel moves exactly 8 times. When it’s the 5th from the end - it moves 5 times.

Can you help a bit? What causes this panel to slide up and down like crazy? Do you have some tips on how to make this work? Maybe there’s something wrong with my code?

My codepen: https://codepen.io/Strzesia/pen/PJVjbR/


#2

$(".online") targets all elements of .online class so every time it’s called it adds the event to the newly created entry and all the previous ones.


#3

I agree with @Quickz, it is most likely because of this line

 $(this).next(".slide").slideToggle("slow");

by utilizing $(this).next(".slide"), I believe it is telling the computer to look for all
divs with the class “slide” that comes after.

Instead of declaring a div with classes ‘status’ online next to the “slide” divs it might be best
to declare the slides as a child div to the status div. That way you can pinpoint which div to toggle.


#4

Hey. You’re in a for loop and the event handler is being attached for each iteration (starting from when the first .online div is found by your selector). If you wrap your .on() method in a console.log, you’ll see something like this:

With this setup, on the first iteration of the for loop, nothing will be attached 'cause the cretation row will have a div with .offline class. Then, on the second iteration, the OgamingSC2 row (which has a div with .online class) is created and so it [the online div] will have an event handler attached. Third iteration, another handler for OgamingSC2.
On the fourth iteration, two .online divs will be found and so each of them will have a handler attached to them and so on until the end of the loop. At the end, OgamingSC2 will have 7 handlers and ESL_SC2 5 of them, making the .slideToggle() fires that amount of times.

Another way of checking for this, is by giving a more easy-to-select class to the element you want to check and using the jQuery data object (that will store any handlers attached to an element) at the end of your code:

streamInfo = "<div class='row streamInfo "+displayName.toLowerCase()+"'>" + profileLogoDiv + nameDiv + statusDiv + "</div>";
  setTimeout(function(){ // Some delay just to wait for the ajax to finish
    console.log($._data( $('.esl_sc2 .online')[0], "events" ));
  },5000)

This will result in something like this:

To solve this, you should remove the click handler from the loop. And, since the .online divs are added dinamically, you would have to attach a delegated event to an already existing element (your #streamers div, for example) that will process the events of the dinamically-added children, like so:

$("#streamers").on('click', '.online', function() {
  $(this).next(".slide").slideToggle("slow");
});

#5

Thank you all, guys!
@Ethanefung, do you think it would be better if the slides were the children of status div than, for example, using .nextUntil?
Wow, @noyb, that was exactly the kind of help I needed. Thank you sooo much for this specific explanation!


#6

I think that @noyb is on point, and it’s best to follow his advice.