jQuery addClass removeClass with timer - javascript

I have an issue with a 'Latest News' module. Please have a look at http://www.proudfootsupermarkets.com/ to see an example of the module (it's the div close to the top of the page which has a large image in it).
At the moment I have it set up so that when a user clicks on a tab the main article shows. The jQuery for this is:
jQuery(document).ready(function() {
$(".moduletable.latestnews article:first-child").addClass("atfront")
$(".moduletable.latestnews article").click(function(){
$(".moduletable.latestnews article").css("zIndex",1).addClass("atback").removeClass("atfront");
$(this).css("zIndex",100).addClass("atfront").removeClass("atback");
});
});
This is all quite simple and straight forward. The problem that I am having is that I want the articles to change automatically after a few seconds. This would then go in an infinite loop starting with article 1 and then after a couple of seconds showing article 2 etc etc...
I am sure that this is fairly simple but I have just about exhausted my knowledge of JavaScript. Thank you for any help that you are able to give :)
I have created a jsfiddle http://jsfiddle.net/Bempv/

You can use setTimeout to change the article in front. If you select the article with the class ".atfront" and then use the .next() selector you should get the functionality you are looking for
$(function(){
var articleToggler = function articleToggler(){
var front = "atfront",
back = "atback";
return function(){
var selection = $(".moduletable.latestnews")
.find("article.atfront")
.addClass(back)
.removeClass(front);
next = selection.next("article");
next = next.length ? next : $(".moduletable.latestnews")
.find("article").first();
next.addClass(front)
.removeClass(back);
console.log(selection.length,next[0])
setTimeout(articleToggler(),1000); //changes every second
};
};
//start the rotation
(articleToggler())();
});
The setTimeout will call the function passed as the first argument once the timeout expires. The timeout argument is in miliseconds so the above code wait for 1 second before calling the function. Since the above function adds it self as the callback this will repeat indefinately

Related

SetInterval loop relatively confusing to me

HTML
<div id="backspace" ng-click="deleteString(''); decrementCursor();">
JS
<script>
$scope.deleteString = function() {
if($scope.cursorPosVal > 0){
//$scope.name = $scope.name - letter;
$scope.name = [$scope.name.slice(0, $scope.cursorPosVal - 1) + $scope.name.slice($scope.cursorPosVal)].join('');
console.log($scope.name);
setTimeout(function(){ setCaretPosition("inputBox", $scope.cursorPosVal); }, 30);
} else {
$scope.cursorPosVal = 1;
}
};
</script>
I am designing an on screen touchscreen keyboard. This is my backspace button. I am going to make it so that when you click and hold the backspace button, it starts removing characters automatically. I don't know where to begin with creating a setInterval, and I know a setInterval is exactly what I need to use here.
If I'm not wrong, you want that while you're keeping your button pressed, a function repeats itself.
You're right with setInterval(). However, the way you manage the event is wrong.
Take a look at this fiddle (It's not your code, but a simple example is the best way to understand):
http://jsfiddle.net/daq9atdd/1/
$(function(){
var interval = null;
$('#myButton').mousedown(function(){
interval = setInterval(function(){
console.log('Hello !');
}, 250);
});
$('#myButton').mouseup(function(){
clearInterval(interval);
});
});
I start the interval when the button is pressed, store it, and clear it when the button is released.
You’re so sure about setInterval.
If browser briefly hangs for whatever reason (say some background task), setInterval would go on queueing your backspace calls until it has some CPU time. This means user may see no change and hold backspace longer than needed, and then see a whole bunch of characters suddenly vanish when browser is back to normal.
Thus by setting a timeout after every call you’re making sure user won’t remove more characters than needed. Might be important if the goal is to improve UX.
Example implementation with AngularJS directives and setTimeout
See also:
setTimeout or setInterval?
noKid’s fiddle updated with setTimeout in mind

force DOM redraw with javascript on demand

The title of the question expresses what I think is the ultimate question behind my particular case.
My case:
Inside a click handler, I want to make an image visible (a 'loading' animation) right before a busy function starts. Then I want to make it invisible again after the function has completed.
Instead of what I expected I realize that the image never becomes visible. I guess that this is due to the browser waiting for the handler to end, before it can do any redrawing (I am sure there are good performance reasons for that).
The code (also in this fiddle: http://jsfiddle.net/JLmh4/2/)
html:
<img id="kitty" src="http://placekitten.com/50/50" style="display:none">
<div>click to see the cat </div>
js:
$(document).ready(function(){
$('#enlace').click(function(){
var kitty = $('#kitty');
kitty.css('display','block');
// see: http://unixpapa.com/js/sleep.html
function sleepStupidly(usec)
{
var endtime= new Date().getTime() + usec;
while (new Date().getTime() < endtime)
;
}
// simulates bussy proccess, calling some function...
sleepStupidly(4000);
// when this triggers the img style do refresh!
// but not before
alert('now you do see it');
kitty.css('display','none');
});
});
I have added the alert call right after the sleepStupidly function to show that in that moment of rest, the browser does redraw, but not before. I innocently expected it to redraw right after setting the 'display' to 'block';
For the record, I have also tried appending html tags, or swapping css classes, instead of the image showing and hiding in this code. Same result.
After all my research I think that what I would need is the ability to force the browser to redraw and stop every other thing until then.
Is it possible? Is it possible in a crossbrowser way? Some plugin I wasn't able to find maybe...?
I thought that maybe something like 'jquery css callback' (as in this question: In JQuery, Is it possible to get callback function after setting new css rule?) would do the trick ... but that doesn't exist.
I have also tried to separte the showing, function call and hiding in different handlers for the same event ... but nothing. Also adding a setTimeout to delay the execution of the function (as recommended here: Force DOM refresh in JavaScript).
Thanks and I hope it also helps others.
javier
EDIT (after setting my preferred answer):
Just to further explain why I selected the window.setTimeout strategy.
In my real use case I have realized that in order to give the browser time enough to redraw the page, I had to give it about 1000 milliseconds (much more than the 50 for the fiddle example). This I believe is due to a deeper DOM tree (in fact, unnecessarily deep).
The setTimeout let approach lets you do that.
Use JQuery show and hide callbacks (or other way to display something like fadeIn/fadeOut).
http://jsfiddle.net/JLmh4/3/
$(document).ready(function () {
$('#enlace').click(function () {
var kitty = $('#kitty');
// see: http://unixpapa.com/js/sleep.html
function sleepStupidly(usec) {
var endtime = new Date().getTime() + usec;
while (new Date().getTime() < endtime);
}
kitty.show(function () {
// simulates bussy proccess, calling some function...
sleepStupidly(4000);
// when this triggers the img style do refresh!
// but not before
alert('now you do see it');
kitty.hide();
});
});
});
Use window.setTimeout() with some short unnoticeable delay to run slow function:
$(document).ready(function() {
$('#enlace').click(function() {
showImage();
window.setTimeout(function() {
sleepStupidly(4000);
alert('now you do see it');
hideImage();
}, 50);
});
});
Live demo
To force redraw, you can use offsetHeight or getComputedStyle().
var foo = window.getComputedStyle(el, null);
or
var bar = el.offsetHeight;
"el" being a DOM element
I do not know if this works in your case (as I have not tested it), but when manipulating CSS with JavaScript/jQuery it is sometimes necessary to force redrawing of a specific element to make changes take effect.
This is done by simply requesting a CSS property.
In your case, I would try putting a kitty.position().left; before the function call prior to messing with setTimeout.
What worked for me is setting the following:
$(element).css('display','none');
After that you can do whatever you want, and eventually you want to do:
$(element).css('display','block');

Trigger event on animation complete (no control over animation)

I've a scenario that requires me to detect animation stop of a periodically animated element and trigger a function. I've no control over the element's animation. The animation can be dynamic so I can't use clever setTimeout.
Long Story
The simplified form of the problem is that I'm using a third party jQuery sliding banners plugin that uses some obfuscated JavaScript to slide banners in and out. I'm in need of figuring out a hook on slideComplete sort of event, but all I have is an element id. Take this jsfiddle as an example and imagine that the javascript has been obfuscated. I need to trigger a function when the red box reaches the extremes and stops.
I'm aware of the :animated pseudo selector but I think it will need me to constantly poll the required element. I've gone through this, this, and this, but no avail. I've checked jquery promise but I couldn't figure out to use that in this scenario. This SO question is closest to my requirements but it has no answers.
P.S. Some more information that might be helpful:
The element isn't created by JavaScript, it is present on page load.
I've control over when to apply the plugin (that makes it periodically sliding banner) on the element
Most of the slideshow plugins I have used use changing classes at the end of the animation... You could extend the "addClass" method of jQuery to allow you to capture the class change as long as the plugin you use is using that method like it should:
(function($){
$.each(["addClass","removeClass"],function(i,methodname){
var oldmethod = $.fn[methodname];
$.fn[methodname] = function(){
oldmethod.apply( this, arguments );
this.trigger(methodname+"change");
return this;
}
});
})(jQuery);
I threw together a fiddle here
Even with obfuscated code you should be able to use this method to check how they are sending in the arguments to animate (I use the "options" object when I send arguments to animate usually) and wrap their callback function in an anonymous function that triggers an event...
like this fiddle
Here is the relevant block of script:
(function($){
$.each(["animate"],function(i,methodname){
var oldmethod = $.fn[methodname];
$.fn[methodname] = function(){
var args=arguments;
that=this;
var oldcall=args[2];
args[2]=function(){
oldcall();
console.log("slideFinish");
}
oldmethod.apply( this, args );
return this;
}
});
})(jQuery);
Well since you didn't give any indication as to what kind of animation is being done, I'm going to assume that its a horizontal/vertical translation, although I think this could be applied to other effects as well. Because I don't know how the animation is being accomplished, a setInterval evaluation would be the only way I can guess at how to do this.
var prevPos = 0;
var isAnimating = setInterval(function(){
if($(YOUROBJECT).css('top') == prevPos){
//logic here
}
else{
prevPos = $(YOUROBJECT).css('top');
}
},500);
That will evaluate the vertical position of the object every .5 seconds, and if the current vertical position is equal to the one taken .5 seconds ago, it will assume that animation has stopped and you can execute some code.
edit --
just noticed your jsfiddle had a horizontal translation, so the code for your jsfiddle is here http://jsfiddle.net/wZbNA/3/

Best way to rotate html on a page

I need to be able to rotate between five distinct pieces of html in my webpage every 8 seconds.
What's the best way to do this? JQuery or native JS is fine.
There are definitely a lot of plugins for that.
But here's some basic structure you could use if you want to do it yourself:
// assuming all your divs have the class `rotating-content`:
$(document).ready(function() {
var divs = $('.rotating-content').hide();
var curr_div = divs.first().show();
function nextcontent() {
// hide current div, then move the next one or the first div, and show it
curr_div = curr_div.hide().next().add(divs.first()).first().show();
setTimeout(nextcontent, 5000); // 5 seconds
}
setTimeout(nextcontent, 5000);
});
You mean like a slideshow? You can use jQuery Cycle plugin from malsup,
here's an example: http://jsfiddle.net/JKirchartz/zLekb/ (none of this extra stuff is necessary, this is just an example I've been recycling)
if you want it to change every 8 seconds change timeout to 8000 (it's measured in milliseconds)

How can I reveal content and maintain its visibility when mousing to a child element?

I'm asking a question very similar to this one—dare I say identical?
An example is currently in the bottom navigation on this page.
I'm looking to display the name and link of the next and previous page when a user hovers over their respective icons. I'm pretty sure my solution will entail binding or timers, neither of which I'm seeming to understand very well at the moment.
Currently, I have:
$(document).ready(function() {
var dropdown = $('span.hide_me');
var navigator = $('a.paginate_link');
dropdown.hide();
$(navigator).hover(function(){
$(this).siblings(dropdown).fadeIn();
}, function(){
setTimeout(function(){
dropdown.fadeOut();
}, 3000);
});
});
with its respective HTML (some ExpressionEngine code included—apologies):
<p class="older_entry">Older<span class="hide_me">Older entry:
<br />
{title}</span></p>
{/exp:weblog:next_entry}
<p class="blog_home">Blog Main<span class="hide_me">Back to the blog</span></p>
{exp:weblog:prev_entry weblog="blog"}
<p class="newer_entry">Newer<span class="hide_me">Newer entry:
<br />
{title}</span></p>
This is behaving pretty strangely at the moment. Sometimes it waits three seconds, sometimes it waits one second, sometimes it doesn't fade out altogether.
Essentially, I'm looking to fade in 'span.hide_me' on hover of the icons ('a.paginate_link'), and I'd like it to remain visible when users mouse over the span.
Think anyone could help walk me through this process and understand exactly how the timers and clearing of the timers is working?
Thanks so much, Stack Overflow. You guys have been incredible as I walk down this road of learning to make the internet.
If you just want to get it working, you can try to use a tooltip plugin like this one.
If you want to understand how this should be done: first, get rid of the timeout, and make it work without it. The difference (from the user's point of view) is very small, and it simplifies stuff (developing and debugging). After you get it working like you want, put the timeout back in.
Now, the problem is you don't really want to hide the shown element on the navigator mouse-out event. You want to hide it in its own mouse out event. So I think you can just pass the first argument to the navigator hover function, and add another hover to dropdowns, that will have an empty function as a first argument, and the hiding code in its second argument.
EDIT (according to your response to stefpet's answer)
I understand that you DO want the dropdown to disappear if the mouse moves out of the navigator, UNLESS its moved to the dropdown itself. This complicates a little, but here is how it can be done: on both types of items mouse-out event, you set a timer that calls a function that hides the dropdown. lets say the timer is 1 second. on both kind of item mouse-in even, you clear this timer (see the w3school page on timing for syntax, etc). plus, in the navigator's mouse-in you have to show the dropdown.
Another issue with the timer in your code is that it will always execute when mouse-out. Due to the 3 seconds delay you might very well trigger it again when mouse-over but since the timer still exist it will fade out despite you actually have the mouse over the element.
Moving the mouse back and forth quickly will trigger multiple timers.
Try to get it to work without the timer first, then (if really needed) add the additional complexity with the delay (which you must keep track of and remove/reset depending on state).
Here was the final working code, for anyone who comes across this again. Feel free to let me know if I could have improved it in any ways:
$(document).ready(function() {
var dropdown = $('span.hide_me');
var navigator = $('a.paginate_link');
dropdown.hide();
$(navigator).hover(function(){
clearTimeout(emptyTimer);
$(this).siblings(dropdown).fadeIn();
}, function(){
emptyTimer = setTimeout(function(){
dropdown.fadeOut();
}, 500);
});
$(dropdown).hover(function(){
clearTimeout(emptyTimer);
}, function(){
emptyTimer = setTimeout(function(){
dropdown.fadeOut();
}, 500);
});
});

Categories