var start = $('#start_img');
start.on('click', function(){
var piano = $('.piano');
piano.each(function(index){
$(this).hide().delay(700 * index).fadeIn(700*index);
start.off('click');
})
});
You can see that I have used the start.off('click') method, to stop the Event Listener from running again once it has been called. But the thing is, I only want the Event listener to be off during the time that the event is running. So that it cannot be called again while the event is still running. But once the event has finished, I want it to be 'callable' again. Does anyone know how t do this?
other way of doing this (doesn't work neither). Can anyone help me here. The other one is now clear.
var start = $('#start_img');
start.on('click', function() {
var q = 0;
var piano = $('.piano');
if (q === 1) {
return; // don't do animations
}
else{
piano.each(function(index) {
q = 1;
$(this).hide()
.delay(700 * index)
.fadeIn(700 * index, function() {
// remove from each instance when animation completes
q = 0
});
});}
});
You could toggle a class on active elements as well and then you can check for that class and not do anything if it exists
start.on('click', function() {
var piano = $('.piano');
if (piano.hasClass('active')) {
return; // don't do animations
}
piano.each(function(index) {
$(this).addClass('active')
.hide()
.delay(700 * index)
.fadeIn(700 * index, function() {
// remove from each instance when animation completes
$(this).removeClass('active')
});
});
});
For only one object, you could use a global variable for this, in my case, I'll be using isRunning:
var start = $('#start_img');
var isRunning = false;
start.on('click', function(){
if (!isRunning){
isRunning = true;
var piano = $('.piano');
piano.each(function(index){
$(this).hide().delay(700 * index).fadeIn(700*index, function(){
isRunning = false;
});
start.off('click');
});
}
});
This way your app shouldn't run the code until isRunning == false, which should happen after fadeIn is completed.
Syntaxes:
.fadeIn([duration] [,complete]);
.fadeIn(options);
.fadeIn([duration] [,easing] [,complete]);
For two or more objects, Charlietfl's answer should work perfectly.
Related
I want a to have an animation only when seven elements have been click. Here is the code but it doesn't work:
var animp5 = function () {
var i = 0;
$("#ans1_p5").on('click', function () {
i = i + 1;
$("#ans1_p5").fadeOut(800);
$("#correct1_p5").fadeIn(1000);
});
$("#ans2_p5").on('click', function () {
i = i + 1;
$("#ans2_p5").fadeOut(800);
$("#correct2_p5").fadeIn(1000);
});
$("#ans3_p5").on('click', function () {
i = i + 1;
$("#ans3_p5").fadeOut(800);
$("#correct3_p5").fadeIn(1000);
});
$("#ans5_p5").on('click', function () {
i = i + 1;
$("#ans5_p5").fadeOut(800);
$("#correct4_p5").fadeIn(1000);
});
$("#ans7_p5").on('click', function () {
i = i + 1;
$("#ans7_p5").fadeOut(800);
$("#correct5_p5").fadeIn(1000);
});
$("#ans9_p5").on('click', function () {
i = i + 1;
$("#ans9_p5").fadeOut(800);
$("#correct6_p5").fadeIn(1000);
});
$("#ans10_p5").on('click', function () {
i = i + 1;
$("#ans10_p5").fadeOut(800);
$("#correct7_p5").fadeIn(1000);
});
if (i === 7) {
$("#ans4").fadeOut(800);
$("#ans6").fadeOut(800);
$("#ans8").fadeOut(800);
$("#wrong1_p5").fadeIn(1000);
$("#wrong2_p5").fadeIn(1000);
$("#wrong3_p5").fadeIn(1000);
$("#cor_p5").fadeIn(1000);
}
};
I have tried other solutions (like .data('clicked') or .attr('clicked') but they didn't work either.
You can use observer design pattern in javascript to achieve this the right way.
First create handlers, subscribe and execute functions and then you can subscribe waht ever you like in your case its comparison i===7. execute fade.execute after every click to validate.
Also it's advisable to use class selectors than id selectors in your case. As id selectors will be unmanageable and you will end up with a lot of duplicate code.
But for the sake of your question observer is your way to go.
jsFiddle
function Fade() { // Create Fade handlers
this.handlers = []; // observers
}
Fade.prototype = { // define subscribe and execute
subscribe: function(fn) {
this.handlers.push(fn);
},
execute: function(o, thisObj) {
var scope = thisObj || window;
this.handlers.forEach(function(item) {
item.call(scope, o);
});
}
};
var fade = new Fade();
fade.subscribe(function(){ // pass function you want to subscribe
console.log(i);
if(i===7){
$("#ans4").fadeOut(800);
$("#ans6").fadeOut(800);
$("#ans8").fadeOut(800);
$("#wrong1_p5").fadeIn(1000);
$("#wrong2_p5").fadeIn(1000);
$("#wrong3_p5").fadeIn(1000);
$("#cor_p5").fadeIn(1000);
}
});
var animp5 = (function(){
var i = 0;
$("#ans1_p5").on('click',function(){
i=i+1;
$("#ans1_p5").fadeOut(800);
$("#correct1_p5").fadeIn(1000);
fade.execute(); // execute to check if condition met
});
$("#ans2_p5").on('click',function(){
i=i+1;
$("#ans2_p5").fadeOut(800);
$("#correct2_p5").fadeIn(1000);
fade.execute();
});
$("#ans3_p5").on('click', function(){
i=i+1;
$("#ans3_p5").fadeOut(800);
$("#correct3_p5").fadeIn(1000);
fade.execute();
});
$("#ans5_p5").on('click', function(){
i=i+1;
$("#ans5_p5").fadeOut(800);
$("#correct4_p5").fadeIn(1000);
fade.execute();
});
$("#ans7_p5").on('click', function(){
i=i+1;
$("#ans7_p5").fadeOut(800);
$("#correct5_p5").fadeIn(1000);
fade.execute();
});
$("#ans9_p5").on('click', function(){
i=i+1;
$("#ans9_p5").fadeOut(800);
$("#correct6_p5").fadeIn(1000);
fade.execute();
});
$("#ans10_p5").on('click', function(){
i=i+1;
$("#ans10_p5").fadeOut(800);
$("#correct7_p5").fadeIn(1000);
fade.execute();
});
})();
Thanks for your answers.
As I have not much experience working with jquery I was unable to code your solution but I found a new one that works perfect. I put the "if" inside every click function so each time I click, code checks if the condition has been fulfilled and once this happens run the appropriate code.
Thanks again
I can't figure out how to do it.
I have two separate scripts. The first one generates an interval (or a timeout) to run a specified function every x seconds, i.e. reload the page.
The other script contains actions for a button to control (pause/play) this interval.
The pitfall here is that both sides must be asyncronous (both run when the document is loaded).
How could I properly use the interval within the second script?
Here's the jsFiddle: http://jsfiddle.net/hm2d6d6L/4/
And here's the code for a quick view:
var interval;
// main script
(function($){
$(function(){
var reload = function() {
console.log('reloading...');
};
// Create interval here to run reload() every time
});
})(jQuery);
// Another script, available for specific users
(function($){
$(function(){
var $playerButton = $('body').find('button.player'),
$icon = $playerButton.children('i');
buttonAction = function(e){
e.preventDefault();
if ($(this).hasClass('playing')) {
// Pause/clear interval here
$(this).removeClass('playing').addClass('paused');
$icon.removeClass('glyphicon-pause').addClass('glyphicon-play');
}
else {
// Play/recreate interval here
$(this).removeClass('paused').addClass('playing');
$icon.removeClass('glyphicon-play').addClass('glyphicon-pause');
}
},
buttonInit = function() {
$playerButton.on('click', buttonAction);
};
buttonInit();
});
})(jQuery);
You could just create a simple event bus. This is pretty easy to create with jQuery, since you already have it in there:
// somewhere globally accessible (script 1 works fine)
var bus = $({});
// script 1
setInterval(function() {
reload();
bus.trigger('reload');
}, 1000);
// script 2
bus.on('reload', function() {
// there was a reload in script 1, yay!
});
I've found a solution. I'm sure it's not the best one, but it works.
As you pointed out, I eventually needed at least one global variable to act as a join between both scripts, and the use of a closure to overcome asyncronous issues. Note that I manipulate the button within reload, just to remark that sometimes it's not as easy as moving code outside in the global namespace:
Check it out here in jsFiddle: yay! this works!
And here's the code:
var intervalControl;
// main script
(function($){
$(function(){
var $playerButton = $('body').find('button.player'),
reload = function() {
console.log('reloading...');
$playerButton.css('top', parseInt($playerButton.css('top')) + 1);
};
var interval = function(callback) {
var timer,
playing = false;
this.play = function() {
if (! playing) {
timer = setInterval(callback, 2000);
playing = true;
}
};
this.pause = function() {
if (playing) {
clearInterval(timer);
playing = false;
}
};
this.play();
return this;
};
intervalControl = function() {
var timer = interval(reload);
return {
play: function() {
timer.play();
},
pause: function(){
timer.pause();
}
}
}
});
})(jQuery);
// Another script, available for specific users
(function($){
$(function(){
var $playerButton = $('body').find('button.player'),
$icon = $playerButton.children('i'),
interval;
buttonAction = function(e){
e.preventDefault();
if ($(this).hasClass('playing')) {
interval.pause();
$(this).removeClass('playing').addClass('paused');
$icon.removeClass('glyphicon-pause').addClass('glyphicon-play');
}
else {
interval.play();
$(this).removeClass('paused').addClass('playing');
$icon.removeClass('glyphicon-play').addClass('glyphicon-pause');
}
},
buttonInit = function() {
$playerButton.on('click', buttonAction);
interval = intervalControl();
};
buttonInit();
});
})(jQuery);
Any better suggestion is most welcome.
I want to be able to run the below function continuously while the mouse is down. At the moment the function excecutes once per click. I want to be able to continue running the function while mousedown and stop when the mouse is released.
$('#md').mousedown(function(e){
var pCords = e.pageY +e.pageY;
var max = $(document).height()+$(document).width();
var dg = 2*( pCords / max );
$('#div').css({ 'transform':'rotate('+dg+'deg) '});
});
This issue has been addressed in: jQuery continuous mousedown
It will involve setting up a flag that you can set to true when the first mousedown event occurs, and calling a function that only finishes once the flag is set back to false when the mouseup event occurs.
Easy way to do with time delay between execution of event handler:
var timerId = 0;
$('#md').mousedown(function(e){
timerId = setInterval(function() {
var pCords = e.pageY +e.pageY;
var max = $(document).height()+$(document).width();
var dg = 2*( pCords / max );
$('#div').css({ 'transform':'rotate('+dg+'deg) '});
}, 20); // specify the required time delay here
});
$('#md').mouseup(function(e){
clearInterval(timerId);
});
You can do it using a simple semaphore. Here's an example:
var lock = true;
$('#md').mousedown(function() {
lock = false;
setTimeout(function() {
while(!lock) {
// Do your stuff here
}
}, 0);
});
$(document).mouseup(function() {
lock = true;
});
I hope this does the trick.
The setTimeout function detaches the execution of the function and creates an asynchronous process - this makes your code non-blocking.
I'm sure there are more sophisticated ways to solve this problem. It's just that I haven't had my coffee yet. :)
like this? making a global boolean variable to track if mouse is up, then looping your function while mouse is down on that element.
var ismouseup = false;
$(document).ready(function(){
$('#md').mousedown(function(e){
ismouseup = false;
while(!ismouseup)
{
//do your thing
}
});
$('#md').mouseup(function(e){
ismouseup = true;
}
});
--edit: set ismouseup to true when mouseup. sorry.
You can use setTimeout. This will run every 1 sec when mousedown
$('#md').on({
mousedown: function () {
$(this).data('clicked', true);
var process = function() {
if ($(this).data('clicked')) {
// Do your stuff
setTimeout(process, 100);
}
};
process();
},
mouseup: function () {
$(this).data('clicked', false);
}
});
As an option you can set the handler for mousemove in mousedown and remove in mouseup as in code
function movehandler(e) {
var pCords = e.pageY + e.pageY;
var max = $('#md').height();
var dg = 20 * (pCords / max);
$('#md').css({
'transform': 'rotate(' + dg + 'deg) '
});
}
$('#md').mousedown(function (e) {
$('body').on('mousemove', movehandler);
});
$('#md').mouseup(function (e) {
$('body').off('mousemove');
});
$('body').mouseleave(function (e) {
$('body').off('mousemove');
});
Jsfiffle Example is not ideally written but you can get the idea
EDIT: Note that $('body').on('mousemove', might not be sufficient dependent on your markup.
I made a control (numeric spinner up and down), to work in a table:
JSFIDDLE: http://jsfiddle.net/Leandro1981/wn8vd/1/
and I want simulate the "mousedown, increment while mouse button is helding" but I can't do it. I tried to mix it with the following and functional script:
JSFIDDLE: http://jsfiddle.net/Leandro1981/kKW85/
but I couldn't make it.
My last attempt here:
http://jsfiddle.net/Leandro1981/S8Zt9/1/
Maybe the wrong is the
timeout = setInterval(function () {
But I couldn't figure out. I'm using bootstrap 3, so I can't use some JQuery UI plugins...
Any help will be preciated!
Please comment below if you have any question, comment or anything to improve this question, and sorry for my english :)
Please be free to use my code/control in any way.
Thanks and kind regards
Write a factory to set up each control so you get a closure over the variables, now it's just a matter of being able to make it work given the relevant elements. For this, you'll need to
Listen for mousedown on the up and down nodes to set off the changes
Start a timeout loop to keep doing your change
Listen for mouseup on window to ensure you cancel the timeout loop (you may also want to listen for mouseout/loss of focus)
So all together,
function spinFactory(node, up, down) { // I wrote this vanilla :D
var spinning, delta;
window.addEventListener('mouseup', stopSpin);
function spin() {
node.value = +node.value + delta;
spinning = setTimeout(spin, 500);
}
function stopSpin() { // maybe also invoke this on mouseout/loss of focus
window.clearTimeout(spinning);
delta = 0;
}
up.addEventListener('mousedown', function spinUp() {
delta = 1;
spin();
});
down.addEventListener('mousedown', function spinDown() {
delta = -1;
spin();
});
}
// apply to your control, used a bit of jQuery to make life easier
$('.PNET-spinner').each(function () {
spinFactory(
this.getElementsByTagName('input')[0],
$(this).find('.btn:first-of-type')[0],
$(this).find('.btn:last-of-type')[0]
);
});
DEMO
I have updated the Fiddle here ... Please check this and it might helps you..
Script
$('.PNET-spinner .btn:first-of-type').on('mousedown', function (e) {
var timer, proxy = this;
timer = setInterval(function () {
increment(proxy);
}, 200);
$(document).one("mouseup", function () {
increment(proxy);
if (timer) clearInterval(timer);
});
});
$('.PNET-spinner .btn:last-of-type').on('mousedown', function () {
var timer, proxy = this;
timer = setInterval(function () {
decrement(proxy);
}, 200);
$(document).one("mouseup", function () {
decrement(proxy);
if (timer) clearInterval(timer);
});
});
function increment(proxy) {
var numupdown = $('.PNET-spinner input', $(proxy).closest("tr"));
var inputValue = parseInt($(numupdown).val(), 10);
inputValue++;
$(numupdown).val(inputValue);
}
function decrement(proxy) {
var numupdown = $('.PNET-spinner input', $(proxy).closest("tr"));
var inputValue = parseInt($(numupdown).val(), 10);
if (inputValue > 1) {
inputValue--;
$(numupdown).val(inputValue);
}
}
You simply need to take care of two things. First, your function to increment and decrement the value in the textbox should be called again and again till user do mouseout or mouseup. Second, make surethis has the right value in var numupdown = $('.PNET-spinner input', $(this).closest("tr"));
Following code shows how to do it for the increment button. Similar thing, you can implement for decrement button.
var timeout;
var inc = function () {
var myThis = this;
var numupdown = $('.PNET-spinner input', $(this).closest("tr"));
var inputValue = parseInt($(numupdown).val(), 10);
inputValue++;
console.log(inputValue);
$(numupdown).val(inputValue);
clearTimeout(timeout);
timeout = setTimeout(function(){
//http://stackoverflow.com/questions/3630054/how-do-i-pass-the-this-context-to-a-function
inc.apply(myThis, arguments);
}, 1000);
};
var incStop = function(){
clearTimeout(timeout);
}
$('.PNET-spinner .btn:first-of-type').on('mousedown', inc);
$('.PNET-spinner .btn:first-of-type').on('mouseup', incStop);
$('.PNET-spinner .btn:first-of-type').on('mouseout', incStop);
Check this DEMO here.
I was wondering if there is a function to be run after an element (e.g. div class="myiv") is hovered and check every X milliseconds if it's still hovered, and if it is, run another function.
EDIT: This did the trick for me:
http://jsfiddle.net/z8yaB/
For most purposes in simple interfaces, you may use jquery's hover function and simply store in a boolean somewhere if the mouse is hover. And then you may use a simple setInterval loop to check every ms this state. You yet could see in the first comment this answer in the linked duplicate (edit : and now in the other answers here).
But there are cases, especially when you have objects moving "between" the mouse and your object when hover generate false alarms.
For those cases, I made this function that checks if an event is really hover an element when jquery calls my handler :
var bubbling = {};
bubbling.eventIsOver = function(event, o) {
if ((!o) || o==null) return false;
var pos = o.offset();
var ex = event.pageX;
var ey = event.pageY;
if (
ex>=pos.left
&& ex<=pos.left+o.width()
&& ey>=pos.top
&& ey<=pos.top+o.height()
) {
return true;
}
return false;
};
I use this function to check that the mouse really leaved when I received the mouseout event :
$('body').delegate(' myselector ', 'mouseenter', function(event) {
bubbling.bubbleTarget = $(this);
// store somewhere that the mouse is in the object
}).live('mouseout', function(event) {
if (bubbling.eventIsOver(event, bubbling.bubbleTarget)) return;
// store somewhere that the mouse leaved the object
});
You can use variablename = setInterval(...) to initiate a function repeatedly on mouseover, and clearInterval(variablename) to stop it on mouseout.
http://jsfiddle.net/XE8sK/
var marker;
$('#test').on('mouseover', function() {
marker = setInterval(function() {
$('#siren').show().fadeOut('slow');
}, 500);
}).on('mouseout', function() {
clearInterval(marker);
});
jQuery has the hover() method which gives you this functionality out of the box:
$('.myiv').hover(
function () {
// the element is hovered over... do stuff
},
function () {
// the element is no longer hovered... do stuff
}
);
To check every x milliseconds if the element is still hovered and respond adjust to the following:
var x = 10; // number of milliseconds
var intervalId;
$('.myiv').hover(
function () {
// the element is hovered over... do stuff
intervalId = window.setInterval(someFunction, x);
},
function () {
// the element is no longer hovered... do stuff
window.clearInterval(intervalId);
}
);
DEMO - http://jsfiddle.net/z8yaB/
var interval = 0;
$('.myiv').hover(
function () {
interval = setInterval(function(){
console.log('still hovering');
},1000);
},
function () {
clearInterval(interval);
}
);