Click counter, different events per click - javascript

I am seeking to create an array that counts and keep tracks of clicks done to a certain area of the page; I would then like each amount of click to do something. Eg.) The 5th click a sound via mp3 triggers. The sixth click the page shakes.
How could I write an array to add different events per a number of clicks, assigning something to a specific number of clicks?

var clicks = 0;
$('a').click(function() {
switch(++clicks) {
case X:
/* do something */
break;
/* ... */
}
});
Or you can store functions in array
var myEvents = [function1, function2, function3];
var clicks = -1;
$('a').click(function() {
clicks++;
if(myEvents[clicks] != undefined) myEvents[clicks]();
});

http://jsbin.com/izutav/1/edit
By simply creating an array of your events functions:
var a1_Events = [shake, noise, something],
a1_c = 0;
function shake(){
alert('SHAKING!');
}
function noise(){
alert('BZZZZZZZZZZZ!');
}
function something(){
alert('SOMETHING ELSE!');
}
$('#area1').click(function(){
a1_Events[a1_c++ % a1_Events.length]();
});
If you don't want to loop your events than use just: a1_Events[a1_c++]();

Something like this!
var actions = {
5: 'playMusic',
6: 'shakeDiv'
},
actors = {
doNothing: function() {/*default action; do nothing;*/},
playMusic: function() {
alert('Your are about to here a music now');
/*place code for playing music here*/
},
shakeDiv: function() {
alert('page is about to shake');
/* place shake animation code here*/
}
},
defaultActionName = 'doNothing';//default action name
var clickCount = 0;
$('yourSelectorForThepart').click(function(e) {
clickCount++;
doAction();
});
function doAction() {
var actionName = actions[clickCount] || defaultActionName;
actors[actionName]();
}
And yes, you could just merge actions & actors. But i prefer this approach for maintenance & readability.

You could do it like this:
// put your click actions as functions here
var clickEvents = [function1, function2, function3, function4, playMP3, shakePage];
var clicks = 0;
// put your clickable object here
clickableObject.onclick = function(){
clickEvents[clicks]();
clicks++;
}

Related

temporarily stopping function jquery

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.

How to have multiple instances of a jQuery plugin

I am trying to create a SoundCloud music player. It can play any track from SoundCloud, but this plugin is only working if there is only one instance of it in the page. So it wont work if two of the same plugin are in the page.
Here is an example of having two players in the page: JSFiddle
var trackURL = $(".player").text();
$(".player").empty();
$(".player").append("<div class='playBTN'>Play</div>");
$(".player").append("<div class='title'></div>");
var trackId;
SC.get('/resolve', { url: trackURL }, function (track) {
var trackId = track.id;
//var trackTitle = track.title;
$(".title").text(track.title);
$(".playBTN").on('click tap', function () {
//trackId = $(".DSPlayer").attr('id');
stream(trackId);
});
// first do async action
SC.stream("/tracks/" + trackId, {
useHTML5Audio: true,
preferFlash: false
}, function (goz) {
soundToPlay = goz;
sound = soundToPlay;
scTrack = sound;
//updater = setInterval( updatePosition, 100);
});
});
var is_playing = false,
sound;
function stream(trackId) {
scTrack = sound;
if (sound) {
if (is_playing) {
sound.pause();
is_playing = false;
$(".playBTN").text("Play");
} else {
sound.play();
is_playing = true;
$(".playBTN").text("Pause");
}
} else {
is_playing = true;
}
}
If you remove any of these div elements that hold the .player class, the other element will work. So it only doesn't work because there are two instances of the same plugin.
How can I fix it? to have multiple instances of the player in one page?
I have identified the problem. It has to do with the fact that you are trying to load multiple tracks at the same time, but have not separated the code to do so.
As #Greener mentioned you need to iterate over the .player instances separately and execute a SC.get() for each one of them.
Here is what I see happening that is causing the problem:
var trackURL = $(".player").text();
^The code above returns a string that contains both of the URLs you want to use back-to-back without spaces. This creates a problem down the road because of this code:
SC.get('/resolve', { url: trackURL }, function (track) {...
That is a function that is trying to load the relevant song from SoundCloud. You are passing it a variable "trackURL" for it to try and load a specific URL. The function gets a string that looks like "URLURL" what it needs is just "URL".
What you can do is iterate over all the different ".player" elements that exist and then call the sounds that way. I modified your script a little to make it work using a for loop. I had to move the "empty()" functions into the for loop to make it work correctly. You have to use .eq(index) when referring to JQuery array of elements.
Like this:
var trackURL
var trackId;
for(index = 0; index < $(".player").length; index++){
trackURL = $(".player").eq(index).text();
//alert(trackURL);
$(".player").eq(index).empty();
$(".player").eq(index).append("<div class='playBTN'>Play</div>");
$(".player").eq(index).append("<div class='title'></div>");
SC.get('/resolve', { url: trackURL }, function (track) {
var trackId = track.id;
alert(track.id);
//var trackTitle = track.title;
$(".title").eq(index).text(track.title);
$(".playBTN").eq(index).on('click tap', function () {
//trackId = $(".DSPlayer").attr('id');
stream(trackId);
});
// first do async action
SC.stream("/tracks/" + trackId, {
useHTML5Audio: true,
preferFlash: false
}, function (goz) {
soundToPlay = goz;
sound = soundToPlay;
scTrack = sound;
//updater = setInterval( updatePosition, 100);
});
});
}
This is not a completely finished code here, but it will initiate two separate songs "ready" for streaming. I checked using the commented out alert what IDs SoundCloud was giving us (which shows that its loaded now). You are doing some interesting stuff with your streaming function and with the play and pause. This should give you a good idea on what was happening and you can implement your custom code that way.

Restart a jQuery function

In my game I have a startGame() function which initializes all the key functions that start the game. At the beginning, you press the start button to take you to the game. Once the game is complete the restart button appears. When this is clicked it takes you back to the start screen, where the start button is.
Ideally I would like at this point to be able to click the start button for the second time, and a new game appear. The problem is that it brings the old game up. I have tried to use .empty, .queue and .dequeue and reset, but nothing seems to work.
How can I restart all the functions when the restart-button is clicked?
$(document).ready(function () {
successSound = $("#successSound")[0];
failSound = $("#failSound")[0];
moveSound = $("#moveSound")[0];
hitSound = $("#hitSound")[0];
missSound = $("#missSound")[0];
hintSound = $("#hintSound")[0];
hintPic = $("#hintPic")[0];
hintPicTitle = $("#hintPicTitle")[0];
bgMusic = $('#audio-bg')[0];
newGame();
//Click event to start the game
$(".start-btn-wrapper").click(function () {
startplay();
});
//Click event to restart the game
$(".restart-btn").click(function () {
restartplay();
});
Fiddle with script in: http://jsfiddle.net/rVaFs/
It will be much easier if you stop using globals: everything not prefixed with var (including functions).
If your startplay depends on initial DOM state, and it’s too difficult (or just takes too much time) to rewrite the code, you can just make a copy of that part of DOM before starting game and delete it on finish.
You could use the document.ready callback to reset everything back to it's original state, by naming the callback function:
$(document).ready(function reset()
{
//your code here
//note, you must ensure event handlers are unbound:
$('#reset').unbind('click').bind('click',reset);//<-- call main callback
});
Another thing you have to keep in mind is that you're creating a lot of implied globals, which could cause problems if you were to use the ready callback. To address this, do change these lines: successSound = $("#successSound")[0]; to var successSound = $("#successSound")[0];.
I created a function called resetGame() and cleared the DOM:
function resetGame() {
$(document).ready();
$('.table-container').empty();
$('.reveal-wrapper').empty();
$('.helper').removeClass('inactive');
$('.tiles-wrapper').removeClass('active');
$('.hint-container').removeClass('active');
$('td').addClass('highlight-problem');
$('.game').removeClass("active").removeClass('game-over').addClass('standby').addClass('transition');
$('.score').html("");
$(".next-question").removeClass('move-down');
$('.reveal-wrapper').removeClass('image' + randomNumber);
$(bgMusic).unbind();
score.right = 0;
score.wrong = 0;
}
function newGame() {
randomWord = [];
listOfWords = [];
attemptNumber = [];
completionNumber = [];
populationNumber = [];
gridSize = [];
createGrid();
backGroundImage();
dragEvent();
nextQuestion();
closeMessage();
replaySound();
$('.score').html("0/" + completionNumber);
$('.game').removeClass("standby").addClass('active').addClass('transition');
$(bgMusic).on('timeupdate', function () {
var vol = 1,
interval = 250;
if (bgMusic.volume == 1) {
var intervalID = setInterval(function () {
if (vol > 0) {
vol -= 0.05;
bgMusic.volume = vol.toFixed(2);
} else {
clearInterval(intervalID);
}
}, interval);
}
});
}
$(document).ready(function () {
successSound = $("#successSound")[0];
failSound = $("#failSound")[0];
moveSound = $("#moveSound")[0];
hitSound = $("#hitSound")[0];
missSound = $("#missSound")[0];
hintSound = $("#hintSound")[0];
hintPic = $("#hintPic")[0];
hintPicTitle = $("#hintPicTitle")[0];
bgMusic = $('#audio-bg')[0];
backGroundSound();
playBackGroundSound();
keyPress();
$(".start-btn-wrapper").click(function () {
newGame();
});
$(".restart-btn").click(function () {
resetGame();
});
});
I then called it in the restart-btn click event.

How to detect if some text box is changed via external script?

I have some jQuery plugin that changes some elements, i need some event or jQuery plugin that trigger an event when some text input value changed.
I've downloaded jquery.textchange plugin, it is a good plugin but doesn't detect changes via external source.
#MSS -- Alright, this is a kludge but it works:
When I call boxWatcher() I set the value to 3,000 but you'd need to do it much more often, like maybe 100 or 300.
http://jsfiddle.net/N9zBA/8/
var theOldContent = $('#theID').val().trim();
var theNewContent = "";
function boxWatcher(milSecondsBetweenChecks) {
var theLoop = setInterval(function() {
theNewContent = $('#theID').val().trim();
if (theOldContent == theNewContent) {
return; //no change
}
clearInterval(theLoop);//stop looping
handleContentChange();
}, milSecondsBetweenChecks);
};
function handleContentChange() {
alert('content has changed');
//restart boxWatcher
theOldContent = theNewContent;//reset theOldContent
boxWatcher(3000);//3000 is about 3 seconds
}
function buttonClick() {
$('#theID').value = 'asd;lfikjasd;fkj';
}
$(document).ready(function() {
boxWatcher(3000);
})
try to set the old value into a global variable then fire onkeypress event on your text input and compare between old and new values of it. some thing like that
var oldvlaue = $('#myInput').val();
$('#myInput').keyup(function(){
if(oldvlaue!=$('#myInput').val().trim())
{
alert('text has been changed');
}
});
you test this example here
Edit
try to add an EventListner to your text input, I don't know more about it but you can check this Post it may help
Thanks to #Darin because of his/her solution I've marked as the answer, but i have made some small jQuery plugin to achieve the same work named 'txtChgMon'.
(function ($) {
$.fn.txtChgMon = function (func) {
var res = this.each(function () {
txts[0] = { t: this, f: func, oldT: $(this).val(), newT: '' };
});
if (!watchStarted) {
boxWatcher(200);
}
return res;
};
})(jQuery);
var txts = [];
var watchStarted = false;
function boxWatcher(milSecondsBetweenChecks) {
watchStarted = true;
var theLoop = setInterval(function () {
for (var i = 0; i < txts.length; i++) {
txts[i].newT = $(txts[i].t).val();
if (txts[i].newT == txts[i].oldT) {
return; //no change
}
clearInterval(theLoop); //stop looping
txts[i].f(txts[i], txts[i].oldT, txts[i].newT);
txts[i].oldT = $(txts[i].t).val();
boxWatcher(milSecondsBetweenChecks);
return;
}
}, milSecondsBetweenChecks);
}

Javascript "while hovered" loop

Can anybody help me on this one...I have a button which when is hovered, triggers an action. But I'd like it to repeat it for as long as the button is hovered.
I'd appreciate any solution, be it in jquery or pure javascript - here is how my code looks at this moment (in jquery):
var scrollingposition = 0;
$('#button').hover(function(){
++scrollingposition;
$('#object').css("right", scrollingposition);
});
Now how can i put this into some kind of while loop, so that #object is moving px by px for as #button is hovered, not just when the mouse enters it?
OK... another stab at the answer:
$('myselector').each(function () {
var hovered = false;
var loop = window.setInterval(function () {
if (hovered) {
// ...
}
}, 250);
$(this).hover(
function () {
hovered = true;
},
function () {
hovered = false;
}
);
});
The 250 means the task repeats every quarter of a second. You can decrease this number to make it faster or increase it to make it slower.
Nathan's answer is a good start, but you should also use window.clearInterval when the mouse leaves the element (mouseleave event) to cancel the repeated action which was set up using setInterval(), because this way the "loop" is running only when the mouse pointer enters the element (mouseover event).
Here is a sample code:
function doSomethingRepeatedly(){
// do this repeatedly when hovering the element
}
var intervalId;
$(document).ready(function () {
$('#myelement').hover(function () {
var intervalDelay = 10;
// call doSomethingRepeatedly() function repeatedly with 10ms delay between the function calls
intervalId = setInterval(doSomethingRepeatedly, intervalDelay);
}, function () {
// cancel calling doSomethingRepeatedly() function repeatedly
clearInterval(intervalId);
});
});
I created a sample code on jsFiddle which demonstrates how to scroll the background-image of an element left-to-right and then backwards on hover with the code shown above:
http://jsfiddle.net/Sk8erPeter/HLT3J/15/
If its an animation you can "stop" an animation half way through. So it looks like you're moving something to the left so you could do:
var maxScroll = 9999;
$('#button').hover(
function(){ $('#object').animate({ "right":maxScroll+"px" }, 10000); },
function(){ $('#object').stop(); } );
var buttonHovered = false;
$('#button').hover(function () {
buttonHovered = true;
while (buttonHovered) {
...
}
},
function () {
buttonHovered = false;
});
If you want to do this for multiple objects, it might be better to make it a bit more object oriented than a global variable though.
Edit:
Think the best way of dealing with multiple objects is to put it in an .each() block:
$('myselector').each(function () {
var hovered = false;
$(this).hover(function () {
hovered = true;
while (hovered) {
...
}
},
function () {
hovered = false;
});
});
Edit2:
Or you could do it by adding a class:
$('selector').hover(function () {
$(this).addClass('hovered');
while ($(this).hasClass('hovered')) {
...
}
}, function () {
$(this).removeClass('hovered');
});
var scrollingposition = 0;
$('#button').hover(function(){
var $this = $(this);
var $obj = $("#object");
while ( $this.is(":hover") ) {
scrollingposition += 1;
$obj.css("right", scrollingposition);
}
});

Categories