How to toggle the class of elements in sequence?
Asked Answered
A

4

9

I am trying to have the class of each elements change one at a time in sequence automatically. This means element 1 glows then goes off as element 2 glows and then goes off and so on. When each element has glowed once the whole sequence starts over.

$('header div:first').toggleClass('highlight').nextAll().toggleClass('none');

function highlight() {
  var $off = $('header div.highlight').toggleClass('none');

  if ($off.next().length) {
    $off.next().toggleClass('none');
  } else {
    $off.prevAll().last().toggleClass('highlight');
  }
}

$(document).ready(function() {
  setInterval(highlight, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
 <div>element 1</div>
 <div>element 2</div>
 <div>element 3</div>
 <div>element 4</div>
</header>

It wont work as expected (elements 2 through 4 highlight all at the same time and then go off while element 1 doesnt change at all) and I dont know why. What am I doing wrong?

Aback answered 5/5, 2016 at 18:45 Comment(6)
I think that extra .none is useless. All you need is your .highlightPieper
should I take it off from where?Aback
Everywhere, unless you include some CSS in your question that demonstrates it has an actual purpose. Just toggle your highlight class instead.Duodenary
@RokoC.Buljan "Copy snippet to answer" button saves timeWindhoek
@HorsSujet woopsz sorrree :) I see now Good job!Pieper
You can use .queue() , .promise()Enriqueenriqueta
P
5

So yes, you don't need the .none. Simply use your default styles and the .highlight class.
Get the number of items, create a counter, increment it and loop it using % Reminder Operator:

jQuery(function( $ ) { // DOM is ready

  var $el = $("header>div"), tot = $el.length, c = 0;

  $el.eq(c).addClass("highlight"); // initial highlight

  setInterval(function() {
    $el.removeClass("highlight").eq(++c%tot).addClass("highlight");
  }, 1000);

});
header > div           { transition:0.5s; -webkit-transition:0.5s; }
header > div.highlight { color:#f0f; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
 <div>element 1</div>
 <div>element 2</div>
 <div>element 3</div>
 <div>element 4</div>
</header>

Some docs:
https://api.jquery.com/eq/
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Remainder_()

Pieper answered 5/5, 2016 at 19:4 Comment(6)
Seems pretty elegant but will this CSS3 stuff work in all browsers?Impropriety
@AlexanderDixon yes, in all modern browsers. And even in IE<9... just without the fade efxPieper
your code is almost the better one. Just one issue, the sequence starts from element 2. Any way to start from element 1 instead?Aback
nevermind. I just realized you added the class to the first element and with that it works as expected. However, I cant change the class of the divs in the html because its an external include. Any way to make it work without changing the html?Aback
Please say more about what you're doing in with the .eq() methods and the counter modulus. I've never seen it used in such a way.Impropriety
that did it. Thank you!Aback
N
4

The none class along with the toggleClass() calls can be a bit confusing to read through. You may be better off by simply keeping track of your current highlighted element via div.highlight and determining which one to target next using the updated code below :

function highlight() {
    // Remove the highlight from all options
    var $current = $('div.highlight');
    // Store the next one
    var $next = $current.next('div');
    // Remove all highlighting
    $('div.highlight').removeClass('highlight')
    if($next.length){
      $next.addClass('highlight');
    } else {
      $('header div:first').addClass('highlight');
    }
}
// When the document is ready
$(function() {
    // Initially set your first element as highlighted and start your interval
    $('header div:first').addClass('highlight');
    setInterval(highlight, 1000);
});

Example

You can see an example of this in action here and demonstrated below :

enter image description here

Image is for example purposes only and timing may appear different than actual code executing... :)

Northwester answered 5/5, 2016 at 18:59 Comment(5)
Parsing the DOM over and over again inside a loop is not the best idea.Pieper
@AlexanderDixon It's a .gif and I'm apparently not great at making perfect ones... I up-voted your comment hoping it was just trolling (the demo itself should look just fine).Northwester
@AlexanderDixon LOL :D just see jsBin Demo, because this jumpy!! just in Gif picture my friend, i think you should undo downvote !Draggle
If Rion adds in a sinppet that says "below is a image sample" I can upvote. Sorry RionImpropriety
I added a little sentence underneath just for you @AlexanderDixon :)Northwester
W
3

Solution :

Change .none by .highlight, like this :

$('header div:first').toggleClass('highlight');

function highlight() {
  var $off = $('header div.highlight').toggleClass('highlight');

  if ($off.next().length) {
    $off.next().toggleClass('highlight');
  } else {
    $off.prevAll().last().toggleClass('highlight');
  }
}

$(document).ready(function() {
  setInterval(highlight, 1000);
});
.highlight {
   color:red; 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
 <div>element 1</div>
 <div>element 2</div>
 <div>element 3</div>
 <div>element 4</div>
</header>

Other ways :

$('header div:first').toggleClass('highlight');

setInterval(function() {
  var abc = "highlight";
      $off = $('header div.' + abc),
      $next = $off.next().length ? $off.next() : $off.prevAll().last();

  $off.toggleClass(abc);
  $next.toggleClass(abc);
}, 1000);
.highlight {
   color:red; 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
 <div>element 1</div>
 <div>element 2</div>
 <div>element 3</div>
 <div>element 4</div>
</header>
Windhoek answered 5/5, 2016 at 18:55 Comment(5)
Thanks. Your code works perfect but I have one question. You put the javascript inside <head> or right before </body>? Because I tried it on my end and it wont work.Aback
That vanilla JavaScript case selection is tried and true. I so need to incorporate it more in my code to ? write more code : write less code;Impropriety
@CainNuke #10994835 I prefer to let you to make your own choice. If you have several js lib, I advice you to use requirejs.Windhoek
My original code worked included in <head> but yours only works if within body. Is there any reason for that?Aback
@CainNuke I don't know. You can use $(document).load(function() { /* code here */ }); to fix it.Windhoek
F
1

You could try this approach.

Javascript

var highlight = function(){
$('header div').removeClass('highlight');
$('header div').each(function(i,v) {
setTimeout(function(){$(v).prev().toggleClass('highlight');$(v).toggleClass('highlight');}, i*1000);
});
setTimeout(highlight, ($('header div').length)*1000);
};
highlight();

Fiddle

Fecteau answered 5/5, 2016 at 19:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.