JavaScript setInterval will only run jQuery once - javascript

I have a fiddle here: http://jsfiddle.net/justinboyd101/4nrbb/
Here is my question:
Why are my console.log function and my statement to add html to a div working, while it's not running on my other looping jQuery function?
For more details, please read below:
I'm trying to create a news ticker using setInterval. The animation is supposed to slide text in from the right side of the screen, then push the content down, then reset back to its original position. For some reason it will only run animations once. I've set up a simple function where ever interval will gather information from the array and add it to an empty div.
Here is my code if you do not wish to go to jsfiddle:
HTML
<div id="newsValueText" class="newsValueText floatLeft darkBlue">
<ul id="newsTicker" class="newsTicker">
<li name="tick" ph="tick1">We have in-store technical support.</li>
<li name="tick" ph="tick2">Option 2</li>
<li name="tick" ph="tick3">Option 3</li>
<li name="tick" ph="tick4">Option 4</li>
<li name="tick" ph="tick5">Option 5</li>
<li name="tick" ph="tick6">Option 6</li>
</ul>
</div>
<div id="log"></div>
JS
//Get the ticker elements
var tickText = document.getElementById('newsTicker').getElementsByTagName('li');
var tickNum = tickText.length;
//New Array to clear empty data
var tickArry = [];
//Loop through list items and add non-void data to new loop
for(var a = 0; a < tickNum; a++) {
if ($(tickText[a]).html() != '') {
tickArry.push($(tickText[a]));
}
}
//Loop int
var i = 0;
var log = document.getElementById('log');
//Self-invoking function for ticker animation
function animTick() {
console.log($(tickArry[i]));
log.innerHTML += $(tickArry[i]).html();
//Make current tick item fall down
$(tickArry[i]).animate({'padding-top' : '+=50px'}, 500,
function() {
//Once tick item is off screen, reset values
$(this).css({'margin-left' : '9999px', 'padding-top' : '0'});
});
//Increment item
i++;
//If the tick has reach its length then reset
if (i === tickNum) {
i = 0;
//Else call the animation for the next tick
}
}
//Immediately animate in first list item
$(tickArry[i]).animate({'margin-left' : '0px'}, 2000);
//Add a delay
setInterval(animTick, 3000);

What if you include $(tickArry[i]).animate({'margin-left' : '0px'}, 2000); inside your animTick function?
Demo: Fiddle

Use setTimeout() if you are recursively calling the same function.
Your setInterval() alternative would be:
function animTick() {
// Function definition
}
setInterval(animTick, 3000);

Related

How to change the style of HTML list items using setInterval in JavaScript?

I have a HTML code with 3 list items and the ids for my ul is 'exercise6-list'
<ul id="exercise6-list">
<li>List 1</li>
<li>List 2</li>
<li>List 3</li>
</ul>
I need to make each li glow for three seconds and repeat itself
So far I have written:
var moveGlow = function() {
var element = document.querySelector("#exercise6-list");
// ... to make it glow i've so far used .setAttribute("class", "glow")
};
clearInterval(window.interval);
window.interval = setInterval(moveGlow, 3000);
*I'm very new to programming, but thank you for your help
To make a timed function we use setInterval, and add the class "glow" to the current element, and remove that class from the previous one.
To cycle through the elements, we use an index-variable, which increases per cycle and loops back around when necessary.
let index = 0;
let elements = document.querySelector("#exercise6-list").children;
let glowFunc = () => {
if (elements.length <= 0) { // Actually not needed since we know there are 3 elements
index = 0;
return;
}
index %= elements.length; // Map index to valid values
elements[(elements.length + index - 1) % elements.length].classList.remove("glow"); // Remove "glow" from previous element
elements[index].classList.add("glow"); // Add "glow" to current element
++index; // Increase 'index'
};
glowFunc(); // Initial call to "start" it without initial delay
setInterval(glowFunc, 3000); // Make it a timed function
li {transition: background-color 0.2s}
.glow {background-color: orange}
<ul id="exercise6-list">
<li>List 1</li>
<li>List 2</li>
<li>List 3</li>
</ul>
Array.from(element.children).forEach(child => {
child.classList.add('glow');
setTimeout(() => child.classList.remove('class'), 3000);
});
However, I think weird things will happen if you make each li glow for longer than the interval, which you have currently set to 300.
If you use something like jQuery you don't need to iterate manually.
Here is an recursive solution with async await.
var moveGlow = async function() {
var element = document.querySelector(".box");
element.style.background = "green";
await sleep(3000)
element.style.background = "red"
await sleep(3000);
return moveGlow()
}
let sleep = (time) => new Promise(res => setTimeout(res, time))
moveGlow()
.box {
width: 100px;
height: 100px;
background: red;
}
<div class="box">
</div>
Instead of setInterval I used setTimeout since interval keeps running until you stop it, where as timeout only happens once then you have to rerun it.
This code is a recursive function that uses a counter to determine where in the list the loop is currently at.
var parent = document.querySelector("#exercise6-list");
var children = parent.querySelectorAll("li");
var total = children.length;
function glow(counter) {
children.forEach(function(el) {
el.classList.remove("highlight");
});
el = children[counter];
el.classList.add("highlight");
setTimeout(function() {
if (counter < total - 1) {
counter++;
glow(counter);
}
else{
el.classList.remove("highlight");
}
}, 3000);
}
glow(0);
.highlight {
background: red;
color: #fff
}
<ul id="exercise6-list">
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
var d=document.querySelector("#exercise6-list");
d.style="background-color:yellow;"
setTimeout(()=>{
d.style=""
},3000)
//time is measured in milliseconds.. simple math
<div style="background-color:yellow" id="exercise6-list">
<li>Text 1</li>
<li>Text 2</li>
<li>Text 3</li>
</div>

Reiterate only through the first 5 element using jQuery .each

does anybody know how to reiterate through only the first 5 elements using jQuery's each?
$(".kltat").each(function() {
// Only do it for the first 5 elements of .kltat class
}
From the documentation:
We can break the $.each() loop at a particular iteration by making the callback function return false.
Furthermore, the same documentation says of the callback you give to .each:
In the case of an array, the callback is passed an array index and a corresponding array value each time.
So try something like this:
$(".kltat").each(function(index, element) {
// do something
// ...
return index < 4;
});
So after you execute the loop on the fifth time (index will equal 4), the loop will stop. Note that using this n-1 logic is needed because you execute the body of the loop before you evaluate the breaking condition.
$(".kltat").each(function(index, element) {
$(element).css('color', 'red');
return index < 4;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="kltat">Item 1</li>
<li class="kltat">Item 2</li>
<li class="kltat">Item 3</li>
<li class="kltat">Item 4</li>
<li class="kltat">Item 5</li>
<li class="kltat">Item 6</li>
<li class="kltat">Item 7</li>
</ul>
You can implement a counter such as this:
var counter = 1;
$(".kltat").each(function() {
// Only do it for the first 5 elements of .kltat class
if (counter==5) {
return false;
} else {
counter++;
}
}
or something of this sort.
How about using .filter():
$(".kltat").filter(function (i) { return i < 5; })
.each(function () {
// ...
});
$(".kltat").slice(0,5).each(function() {
// Only do it for the first 5 elements of .kltat class
})
And without jquery:
[].slice.call(document.querySelectorAll('.kltat')).slice(0,5).forEach(function (element) {
doStuff(element)
})

Randomize or shuffle <ul>items except list items with a specific class

I have this HTML list <ul> which contains list items with two different classes.
<ul id="Items">
<li class="sw">Switchable 1</li>
<li class="sw">Switchable 2</li>
<li class="notsw">This should remain 3</li>
<li class="sw">Switchable 4</li>
<li class="notsw">This should remain 5</li>
<li class="sw">Switchable 6</li>
</ul>
<input type="button" class="btn" value="Shuffle" />
I am trying to randomize or shuffle the order of the list items when an event is triggered (let's say a button was clicked) but only shuffle the list items with the .sw class. So far, I have achieved shuffling the list items(all of them) using a jQuery custom function. Then, I tried storing the initial indexes of the .notsw list items(I think i'm getting the right values) and used jQuery .before() to move it back after the shuffle but still I can't make it go where it should be.
Note: The list items with the .notsw class could be anywhere in the list initially.
jQuery:
$('.btn').click(function(){
var notsws = document.getElementsByClassName("notsw");
var inds = new Array();
for(var i=0; i<notsws.length; i++){
inds[i] =$('.notsw').eq(i).index();
}
$('#Items').randomize();
for(var k=0; k<notsws.length; k++){
var curr = inds[k];
$('.notsw').eq(k).before($('#Items li').eq(curr));
}
});
$.fn.randomize = function(selector){
var $elems = selector ? $(this).find(selector) : $(this).children(),
$parents = $elems.parent();
$parents.each(function(){
$(this).children(selector).sort(function(){
return Math.round(Math.random()) - 0.5;
}).remove().appendTo(this);
});
return this;
};
I HAVE A JSFIDDLE EXAMPLE HERE
I used an alternate approach. I see that you are randomizing your list and then trying to remember whether the original elements were.
Instead of that, why don't you just shuffle elements based on whether they can be shuffled.
In the sense, take an array of the indexes for the switchable elements denoted by the selector .sw and then shuffle only those indexes.
Here's how the shuffle function would look like.
function shuffle(nodes, switchableSelector) {
var length = nodes.length;
//Create the array for the random pick.
var switchable = nodes.filter("." + switchableSelector);
var switchIndex = [];
$.each(switchable, function(index, item) {
switchIndex[index] = $(item).index();
});
//The array should be used for picking up random elements.
var switchLength = switchIndex.length;
var randomPick, randomSwap;
for (var index = length; index > 0; index--) {
//Get a random index that contains a switchable element.
randomPick = switchIndex[Math.floor(Math.random() * switchLength)];
//Get the next element that needs to be swapped.
randomSwap = nodes[index - 1];
//If the element is 'switchable' continue, else ignore
if($(randomSwap).hasClass(switchableSelector)) {
nodes[index - 1] = nodes[randomPick];
nodes[randomPick] = randomSwap;
}
}
return nodes;
}
On your button click, you can simply shuffle the nodes and then re-append them to the container.
$(".btn").click(function() {
var $nodes = $("#Items").find("li");
shuffle($nodes, "sw");
$("#Items").append($nodes);
});
Working fiddle present here.
What you are doing is removing all the "sw" elements and then pushing them at the back of the list. I would create a new randomized list with the "sw" items and then add the "notsw"item at their previous indexes. You should therefore save the "notsw" indexes.

Click speech bubble to display list items in order - Not working in IE8

I have a list in my HTML with a number of quotes. I have also got a div called "speech" which is styled to look like a speech bubble.
When the program is run the first quote is displayed in the bubble and when it is clicked it skips through the list of quotes.
My issue is that in IE8 nothing is displayed in the bubble and I cannot work out why. Can someone tell me whether I am doing something wrong, or advise me on how to do a better.
Here is the list...
<ul class="facts">
<li>
<span>What goes ho-ho whoosh, ho-ho whoosh?<br/>Santa caught in a revolving door.</span>
</li>
<li>
<span>Whats white and goes up? <br/> A confused snowflake.</span>
</li>
<li>
<span>Which Christmas carols do parents like best? <br/> Silent Night.</span>
</li>
<li>
<span>How did the snowman get to school?<br/>On his icicle.</span>
</li>
<li>
<span>What do you call a three-legged donkey?<br/> A wonkey.</span>
</li>
</ul>
and here is the script...
jQuery.fn.extend({
rnditem : function(l) {
var a = [],
current = jQuery(this).html().trim(),
index,
next;
Array.prototype.forEach.call(l, function(item) {
a.push(jQuery(item).html()
jQuery.trim();
});
index = a.indexOf(current) + 1;
if (index < 0 || index >= l.length) {
index = 0;
}
next = (l.eq(index).html());
jQuery(this).html(next);
return this;
}
});
jQuery(document).ready(function () {
var list = jQuery(".facts").find("li");
jQuery(document.body).on('click','.speech', function () {
jQuery(this).rnditem(list);
});
jQuery(".speech").trigger("click");
});
Fiddle: http://jsfiddle.net/S79qp/425/
Looking at the Fiddle, I see different code than what is posted above.
The lines below
current = jQuery(this).html().trim(),
and
a.push(jQuery(item).html().trim());
would throw an error that would be something like
Object doesn't support property or method 'trim'
because IE8 does not have trim built in, so use jQuery.trim()

sequential effects on list-items in jQuery

here's the snippet of my code :
<ul>
<li>Home</li>
<li>Links</li>
<li>Contact</li>
</ul>
I use css to style them horizontally (menu-like) and what I would like to do is to animate all the list-items of the <ul> element. I top them when the dom is ready and animate them to the bottom to attract users' eyes when the entire page is loaded.
here's the jquery code:
$(function(){
$("ul li").css('top', '-40px'); //items are in relative position
$(window).bind("load", items_animate, false);
});
function items_animate(){
... //I'd like to animate each <li> of the <ul> changing 'top' to '0px' but not simultaneously, I want to declare a DELAY between each animation (<li>'s get down in a row)
}
I know how to sequence effects with queue() or calling functions one by one but on only one element, I'm lost in this case..
EDIT : for those who are interested, here's the code to accomplish this sequence, thanks to Joseph
var animationDelay = 600;
var offset = 200;
function blah(meh) {
setTimeout(function(){
$(meh).animate({
opacity: "0"
}, animationDelay);
},$(meh).index() * offset)
}
$("li").each(function(){
blah(this);
})
Demo
Here is another way (using opacity for clarity) that animates the list items in series with a delay in between.
<ul>
<li>Home</li>
<li>Links</li>
<li>Contact</li>
</ul>
var animationDelay = 600;
var offset = 200;
function blah(meh) {
setTimeout(function(){
$(meh).animate({
opacity: "0"
}, animationDelay);
},$(meh).index() * offset)
}
$("li").each(function(){
blah(this);
})
*pardon the less than original names... it's late :P
function slide_down_recursive(e,duration,callback)
{
$(e).animate(
{
top: '0px'
}, duration, 'linear',function()
{
if($(e).next().length == 0)
{
if(typeof(callback) == 'function')
{
callback();
}
return;
}
else
{
// Apply recursion for every sibling.
slide_down_recursive($(e).next(),duration,callback);
}
});
} // End slide_down_recursive
slide_down_recursive($('li:first-child'),500);
Here is a demo: http://jsfiddle.net/rpvyZ/
Try something like this:
$(function() {
function animateSequentially(element, properties, duration) {
element.animate(properties, duration, function() {
animateSequentially(element.next(), properties, duration);
});
}
animateSequentially($("ul > li:first-child"), {top: '0'}, 1000);
});
Edit: If you'd like them to animate sequentially but not wait for the previous one, you can try this:
$(function() {
$("ul > li").each(function(index, item) {
setTimeout(function() {
$(item).animate({top: '0'}, 500);
}, index*175);
});
});
Try the one that waits here, or the one that doesn't wait here.
Use .animates callback function to animate the next element.
$('li:eq(0)').animate({
top: "0px"
}, 5000, function() {
$('li:eq(1)').animate({
top: "0px"
}, 5000, function() {
...
});
});
as of this request, I wrote a jQuery plugin to walk sequencially through a list of (any) elements and applying css changes.
You can checkout the Plugin here:
https://github.com/ieservices/frontend-components/tree/master/jQuery/Plugins/jquery.list-effects
There I made it quite easy to apply those effects by defining the list and the effect options as a JavaScript object. For the first version I created the possiblity to define the delay of the changes between the elements as well as the options to define a starting index to define on which element the changes should be applied.
With the plugin you can do something like this:
<div id="myList">
<h4>This is my list</h4>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
By applying css stylesheet changes by rotating through the list elements:
jQuery('#myList ul li').listEffect(
{delay: '2000', attribute: 'color', value: '#ccc'}
);
Also I created and a demo in the repo, which is available here:
https://github.com/ieservices/frontend-components/blob/master/jQuery/Plugins/jquery.list-effects/demo/list-effects-demo-simple.html
So, far it can't do much, but what do you guys think of that Plugin?

Categories