Stop function after certain number of clicks on a certain element - javascript

OK so I am making a reaction tester, and I have a function that makes shapes appear on screen, So what I want is some sort of function were after 5 clicks on a certain element it will end a function. Is there a way of doing that? sorry if its a dumb question, its because I am new to the whole coding...

Here you go
var clickHandler = (function (e) {
var count = 0;
return function () {
count += 1;
if (count > 5) {
return;
}
// do other stuff here
}
}());
aDiv.addEventListener('click', clickHandler, false);

You Can use static variable to count how many times the object has been clicked.
and here is how you can create static variable in javascript.

You can unbind the click event once the counter reaches 5. See the example below
function test(sender) {
sender.dataset.clicked++;
console.log("I've been clicked", sender.dataset.clicked);
if (+sender.dataset.clicked === 5) {
// unbind the event
sender.onclick = null;
}
return;
}
<div onclick="test(this);" data-clicked="0">click me</div>

You may use global variable which may remain counting on click function
<script>
var globalvar = 0;
onclickfunct()
{
globalvar += 1;
if(globalvar == 5)
{
//do my work
}
else
{
//give alert
}
}
</script>

Related

How to redirect to another page when reloaded in Javascript?

i have created a variable holding the current location of the page and comparing it to other and reloads the page but the problem is it looks big and it's not so efficient enough as i reload the page is taking some time to show the another webpage
// let Storynumber = ["story1.html", "story2.html", "story3.html"];
let currentLocation = window.location;
var i;
window.onbeforeunload = function () {
if (currentLocation.pathname == "/HTML/story1.html") {
window.setTimeout(function () {
window.location.replace("http://127.0.0.1:5500/HTML/story2.html");
console.log("Working");
});
window.onbeforeunload = null; // necessary to prevent infinite loop, that kills your browser
} else if (currentLocation.pathname == "/HTML/story2.html") {
window.setTimeout(function () {
window.location.replace("http://127.0.0.1:5500/HTML/story3.html");
console.log("Working");
});
window.onbeforeunload = null;
} else if (currentLocation.pathname == "/HTML/story3.html") {
window.setTimeout(function () {
window.location.replace("http://127.0.0.1:5500/HTML/story1.html");
console.log("Working");
});
window.onbeforeunload = null;
} else {
console.log("same page cant be reloaded");
}
};
I can see from your commented out code that you've tried to refactor the conditional statements into an array lookup, so I've gone down this angle.
I'd also recommend using addEventListener instead of directly overwriting onbeforeunload in case you need to bind multiple events.
I'm working under the assumption that your site is running on 127.0.0.1:5500, and that all the pages are stored in the same directory
As #salvo720 pointed out in their answer, setTimeout is unnecessary in this case and could also be leading to delays.
I'd suggest something similar to this:
//array containing our pages
const pages = ["story1.html", "story2.html", "story3.html"];
function redirectToNextPage(){
//get the current page - this grabs just the last part of the URL (e.g. "story1.html" instead of "HTML/story1.html"
const curr = window.location.pathname.split('/').pop();
//work out which page we're on - if curr is "story1.html", this is 0, if curr is "story2.html" this is 1, etc. If it doesn't match, this is -1
let index = pages.indexOf(curr);
if(index < 0 || index >= pages.length){ //if we're either non-matching or on the last element
index = 0; //reset to the first one
} else {
index++; //go to the next one
}
window.removeEventListener('beforeunload', redirectToNextPage); //remove event listener
window.location.replace(pages[index]); //do the redirect to the next page
});
window.addEventListener('beforeunload', redirectToNextPage);
That way, when you need to add "story4.html", you can just add it to your pages array
Something I would question is the use of the beforeunload event to redirect the page, but if it works for you then it works for you!
to eliminate delays, I advise you to delete the window.settimeout() methods , look the event loop javascript I leave you the link here (https://www.javascripttutorial.net/javascript-event-loop/#:~:text=The%20event%20loop%20is%20a,queue%20and%20the%20call%20stack.&text=In%20this%20example%2C%20the%20timeout,before%20the%20message%20%27Bye!%27), try with this code :
// let Storynumber = ["story1.html", "story2.html", "story3.html"];
let currentLocation = window.location;
var i;
window.onbeforeunload = function () {
if (currentLocation.pathname == "/HTML/story1.html") {
window.location.replace("http://127.0.0.1:5500/HTML/story2.html");
console.log("Working");
window.onbeforeunload = null; // necessary to prevent infinite loop, that kills your browser
} else if (currentLocation.pathname == "/HTML/story2.html") {
window.location.replace("http://127.0.0.1:5500/HTML/story3.html");
console.log("Working");
window.onbeforeunload = null;
} else if (currentLocation.pathname == "/HTML/story3.html") {
window.location.replace("http://127.0.0.1:5500/HTML/story1.html");
console.log("Working");
window.onbeforeunload = null;
} else {
console.log("same page cant be reloaded");
}
};
try this:
<!DOCTYPE html>
<html>
<body>
<button onclick="myFunction()">Replace document</button>
<script>
function myFunction() {
location.replace("https:www.url.com")
}
</script>
</body>
</html>

Clearing setInterval() Issue

I have a setInterval on a function X that runs every 500ms. In this function X, I call another function Y that essentially binds an event on some divs. However, I would like to unbind these events the next time the function X is called (to start "fresh"). My code doesn't seem to work:
setInterval(this.board.updateBoard, 500); //called from another constructor
This then initiates the functions below:
Board.prototype.updateBoard = function() {
//I attempt to unbind ALL my divs
var divs = this.$el.find("div");
for(var i = 0; i < divs.length; i++) {
$(divs[i]).unbind(); //Apparently this doesn't work?
}
//...some code here...
//find appropriate $div's (multiple of them), and then calls this.beginWalking() below on each of those
//loop here
this.beginWalking($div, direction + "0", direction + "1");
//end of loop
}
//alternate between classes to give appearance of walking
Board.prototype.beginWalking = function ($div, dir0, dir1) {
return setInterval(function () {
if ($div.hasClass(dir0)) {
$div.removeClass(dir0);
$div.addClass(dir1);
} else {
$div.removeClass(dir1);
$div.addClass(dir0);
}
}.bind(this), 80);
};
Basically, updateBoard is called every 500ms. Each time it's called, beginWalking is called to set another interval on a div. The purpose of this other interval, which functions correctly, is to add and remove a class every 80ms. I just can't seem to unbind everything before the next updateBoard is called.
Any suggestions appreciated!
use clearInterval()
edit: $(selector).toggleClass(dir0) might also be helpful
// In other file, use a global (no var) if you need to read it from another file:
updaterGlobal = setInterval(this.board.updateBoard, 500);
// store interval references for clearing:
var updaterLocals = [];
Board.prototype.updateBoard = function() {
//I attempt to unbind ALL my divs
var divs = this.$el.find("div");
// Stop existing div timers:
while(updaterLocals.length > 0){
clearInterval(updaterLocals[0]);
updaterLocals.shift(); // remove the first timer
}
//...some code here...
//loop here to call the below on several $div's
this.beginWalking($div, direction + "0", direction + "1");
//end of loop
}
//alternate between classes to give appearance of walking
Board.prototype.beginWalking = function ($div, dir0, dir1) {
var interval = setInterval(function () {
if ($div.hasClass(dir0)) {
$div.removeClass(dir0);
$div.addClass(dir1);
} else {
$div.removeClass(dir1);
$div.addClass(dir0);
}
}.bind(this), 80);
// Save the timer:
updaterLocals.push(interval);
return;
};

Cross-browser addevent function javascript

I'm trying to create a function that adds an event to each button in a class. I have all of the buttons in an array and wanted to use Dustin Diaz's addevent() cross browser solution, but am unsure how to implement it. I'm used to using frameworks for this sort of thing, but have to use pure JS for this one.
Any pointers or advice on how to use Dustin's solution would be appreciated.
Ok so after taking #Pointy 's advice, I wrote this that checks for addEventListener and if not uses attachEvent This however is not calling testFunction(). What am I doing wrong here?
function addEvents()
{
var buttonArray=document.getElementsByClassName('mainButton');
for(i=0; i < buttonArray.length; i++)
{
if (i.addEventListener) {
i.addEventListener("click", testFunction);
}
else if (i.attachEvent) {
i.attachEvent("onclick", testFunction);
}
function testFunction() {
alert("Test");
}
}
// Attach an event to each button that when clicked on will display an alert that say 'Button X clicked' where X = the button ID
}
You are trying to add an event to a number. You should replace "i" with "buttonArray[i]" and add an else-case (defensive coding).
function addEvents() {
var buttonArray = document.getElementsByClassName('mainButton');
for(i = 0; i < buttonArray.length; i++) {
if (buttonArray[i].addEventListener) {
buttonArray[i].addEventListener("click", testFunction);
} else if (buttonArray[i].attachEvent) {
buttonArray[i].attachEvent("onclick", testFunction);
} else {
throw new Error("This should be unreachable");
}
}
function testFunction() {
alert("Test");
}
}

Javascript track when element became visible?

I have different controls on screen and hide and show them asynchronously. Is there any way to track when an element becomes actually visible on the screen? I actually want to get a callback when that happens and move the focus on that element!
try this
var trk = new Array("element1","element2","element3"); // add elements IDS whom you want to track
window.onload = function(){
track();
}
function track()
{
var ele;
for(var i=0;i<trk.length;i++)
{
ele= document.getElementById(trk[i]);
if(ele)
{
if(ele.style.display!="none")
{
// do something
}
}
}
setTimeout(function(){track();},1);
}
The only way that I can think of is to have a setInterval method which checks of the element.style.display!=="none", or whatever other method you used to hide and show the element.
Something like:
var myInterval = setInterval(function()
{
var element = document.getElementByID("SomeElement");
if( element.style.display!=="none" || element.style.visibility!=="hidden")
{
//exit the interval
clearInterval(myInterval);
doSomeFunction();
}
}, 20);

Jquery bind not working while within a javascript recursive loop

I am writing a piece of code that changes some lights on a screen from red to green randomly and waits for the user to hit the key that corresponds to the light lit.
When I run this code you are able to hit the a,d,j or l key and an alert will pop up. However, as soon as I click the start button no keys are recognised. And when the loop has finished the bind still seems to become disabled. I have tried moving the bind to other places but I have had no joy. Your help is much appreciated.
$( function() {
$('#start').bind('click', function() { main(); });
$(document).bind('keypress', function(e) { keyPress(e); } );
} );
function getRand(val) {
return Math.floor(Math.random()*val)+1;
}
function main() {
preD = new Date;
preDs = preD.getTime();
randTime=Math.floor(Math.random()*1001)+1500;
playSound();
flash();
}
function flash() {
zone = getZone();
setTimeout(function() {
$('#r'+zone).css("background-image", "url(images/rea_grn.jpg)");
setTimeout(function() {
$('#r'+zone).css("background-image", "url(images/rea_red.jpg)");
if(cond[1] < 8) {
main();
}
} , 200);
} , randTime);
}
function getZone() {
if(condition==1) {
zone = getRand(2);
if( test[1][zone] < 8 ) {
test[1][zone] += 1;
cond[1] += 1;
return zone;
} else {
getZone();
}
}
}
function keyPress(e) {
var evtobj=window.event? event : e //distinguish between IE's explicit event object (window.event) and Firefox's implicit.
var unicode=evtobj.charCode? evtobj.charCode : evtobj.keyCode
var actualkey=String.fromCharCode(unicode)
if (actualkey=="a" || actualkey=="d" || actualkey=="j" || actualkey=="l" ) {
dd = new Date;
reat = dd.getTime();
alert(1);
//keypressed[condition][zone]['k']=actualkey;
//keypressed[condition][zone]['t']=(reat-preDs);
}
}
The reason that this could be happening is, when you generate code dynamically or alter any existing code the bind needs to be done again, because the function to bind just runs once and only for the members already created. So when you create dynamically code, you are forced to run the binding function to recognize the new elements.
this ways is not very recommended, instead of this, you could bind a container like 'div' or something and inside of this validate which element is calling you. This will work because your container is created once and the binding is properly assigned and doesn't matter if the content of your container changes, the binding always work.
Regards
Using a jquery sound plugin was the answer.
Fixed it with this : plugins.jquery.com/project/sound_plugin

Categories

Resources