I have a set of independent functions - fn1(), fn2(), fn3(), fn4().
I only need one function running at a time but the functions should toggle, on click of a single button, in a sequence fn1() [click] fn2() [click] fn3() [click] fn4() [click] back to fn1()
How do I approach this problem?
If I've understood what you're trying to do, you want to run a different function on successive clicks on a single element.
To do that you can put each function in an array, then run through each one using the modulo operator to return to the start of the array once the end is reached, something like this:
var functions = [function() {
console.log('first');
}, function() {
console.log('second');
}, function() {
console.log('third');
}, function() {
console.log('fourth');
}];
$('button').click(function() {
var i = ($(this).data('i') + 1) || 0;
functions[i % functions.length]();
$(this).data('i', i);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click me</button>
You can use a closure to keep track of which function you want to execute.
Html:
<button type="button" onclick="foo()"></button>
Js:
var foo = (function() {
var funcIndex = 0;
return function() {
switch(funcIndex) {
case 0: func1(); break;
case 1: func2(); break;
case 2: func3(); break;
case 3: func4(); break;
}
funcIndex = (funcIndex+1) % 4;
}
})();
function fn1(){}
function fn2(){}
function fn3(){}
var i = 1;
function myclick(){
if (i == 1)
fn1();
elseif (i == 2)
fn2();
elseif (i == 3) {
fn3();
i = 1;
}
i++;
}
Everytime you call myclick, it runs one fn and then adds 1 to i. The next time it runs the 2nd fn, followed by the 3rd.
<button onclick="toogle()">Click Me</button>
Then
var index = 0;
var funcArr= [f1,f2,f3,f4];
function toogle(){
funcArr[index]();
index++;
index = index%funcArr.length;
}
function f1(){console.log("f1")};
function f2(){console.log("f2")};
function f3(){console.log("f3")};
function f4(){console.log("f4")};
https://jsfiddle.net/8chvusaq/
arr=[fn1,fn2,fn3,fn4];
var i=0;
$("buttonId").click(function(){
arr[i%4]();
i++;
})
You can try this approach :
function fn1()
{
//do something
$("#myButton").off("click");
$("#myButton").click(fn2);
}
function fn2()
{
//do something
$("#myButton").off("click");
$("#myButton").click(fn3);
}
function fn3()
{
//do something
$("#myButton").off("click");
$("#myButton").click(fn4);
}
function fn4()
{
//do something
$("#myButton").off("click");
$("#myButton").click(fn1);
}
$("#myButton").click(fn1);
Related
I'm trying to call a function that's returned from a function. Here's what I mean:
myFunction.something; // (Wrong)
function myFunction() {
return {
something: function() {
...
}
};
}
When I try calling myFunction.something nothing happens. How can I call a returned function outside of its function?
JSFiddle
var index = 0;
var animID = requestAnimationFrame(myFunction.something);
function myFunction() {
return {
something: function() {
index++;
console.log(index);
if (index === 5) cancelAnimationFrame(animID);
else animID = requestAnimationFrame(myFunction.something);
}
};
}
I would first of all recommend using descriptive variable names; utils rather than myFunction, and incrementFrame rather than something, for example. I would second of all recommend reconsidering your approach to code organization and simply putting all of your helper functions directly in an object, then referencing that object:
var index = 0;
var animID = requestAnimationFrame(utils.incrementFrame);
var utils = {
incrementFrame: function() {
index++;
console.log(index);
if (index === 5) cancelAnimationFrame(animID);
else animID = requestAnimationFrame(utils.incrementFrame);
}
}
There are a few differences between these approaches, some of them frustratingly subtle. The primary reason I recommend using an object for organization rather than a function which returns an object is because you don't need to use a function for organization; you are unnecessarily complicating your code.
myfunction is not the object that you get from calling myfunction(), it's the function itself and does not have a .something method.
You could call it again (as in myfunction().something()), but a better approach would be to store a reference to the object you've already created:
function myFunction() {
var index = 0;
var o = {
something: function() {
index++;
console.log(index);
if (index < 5) requestAnimationFrame(o.something);
// btw you don't need to cancel anything once you reach 5, it's enough to continue not
}
};
return o;
}
myFunction().something();
Alternatively you might want to drop the function altogether, or use the module pattern (with an IIFE), as you seem to use it like a singleton anyway.
Try this:
myFunction().something()
myFunction() calls the myFunction function
them we use the dot notation on the returned value (which is an object) to find the something member of it
that member is a function too, so add another set of brackets () to call it
Call function after writing it
var index = 0;
function myFunction() {
return {
something: function() {
index++;
console.log(index);
if (index === 5) cancelAnimationFrame(animID);
else animID = requestAnimationFrame(myFunction().something);
}
};
}
var animID = requestAnimationFrame(myFunction().something);
I have a button that I want to switch between 2 different functions when clicked. like first click would call function A, second click would call function B, Third Click would call function A etc.
for html I have something like this:
<input type="image"onclick="test()">
for javascript I have:
<script>
val = 1;
function test () {
if (val = 1 ) {
function1 ();
}
else {
function2 ();}
}
</script>
<script>
function function1() {
alert("1");
val = 2;}
</script>
<script>
function function2() {
alert("2");
val = 1;}
</script>
it only ever runs function1 Even if I set val = 2 it will run function1. any idea what im doing wrong?
You were using the assignment operator to check the value. Use the equality operator instead:
<script>
val = 1;
function test () {
if (val == 1 ) { // compare values using == (or maybe ===)
function1();
val = 2; // use the assignment operator here
}
else {
function2();
val = 1;
}
}
</script>
Update:
As #nnnnnn pointed out, you might want to update your toggle state inside test() directly.
If you need only toggle button, you can try XOR style function.
<script>
val = 0;
function toggle(){
val = val ^ 1; // XOR 0^1 => 1, 1^1 => 0
if(val == 0){
//do something
}else{
//do something else
}
}
</script>
OR in shorter way
<script>
val = 0;
function toggle(){
val = val ^ 1; // XOR 0^1 => 1, 1^1 => 0
val == 0 ? function1(): function2();
}
</script>
Thanks to the help of you fine Overflowians, I fixed up my silly little RNG Addition game and got it working. Now, at one user's suggestion, I'm trying to change the scope of the addition game's code from global to local before I code up the next game; I want each game to be completely contained within its own scope, as I understand that learning to not thoughtlessly contaminate the global scope is a good idea. However, I'm a bit stuck on how to achieve that.
Here's the code for the currently functional addition game:
function beginAdditionChallenge() {
var x = Math.ceil(Math.random()*100);
alert(x);
for (var i = 0; i < 3; i++) {
var a = Number(prompt("Provide the first addend.", ""));
var b = Number(prompt("Provide the second addend.", ""));
if (a + b === x) {
alert("Well done!");
break;
}
else if (a + b !== x && i < 2) {
alert("Please try again.");
}
else {
alert("Derp.");
}
}
}
function initChallenge() {
var button = document.getElementById("challengeButton");
button.addEventListener("click", beginAdditionChallenge);
}
window.addEventListener("load", initChallenge);
And here's my attempt to wrap it, which only succeeds in breaking the game, such that the button doesn't even respond:
window.addEventListener("load", function() {
function beginAdditionChallenge() {
var x = Math.ceil(Math.random()*100);
alert(x);
for (var i = 0; i < 3; i++) {
var a = Number(prompt("Provide the first addend.", ""));
var b = Number(prompt("Provide the second addend.", ""));
if (a + b === x) {
alert("Well done!");
break;
}
else if (a + b !== x && i < 2) {
alert("Please try again.");
}
else {
alert("Derp.");
}
}
}
function initChallenge() {
var button = document.getElementById("challengeButton");
button.addEventListener("click", beginAdditionChallenge);
}
window.addEventListener("load", initChallenge);
});
Functional code is available on JSFiddle here.
Note that the onLoad option in JSFiddle does the same as your 2nd snippet. You'll want to choose one of the No wrap options when binding to 'load' yourself.
And, the issue stems from attempting to bind to 'load' within a 'load' handler:
window.addEventListener("load", function() {
// ...
window.addEventListener("load", initChallenge);
});
When the event is already firing and handling the outer binding, it's too late to add more handlers to it. They won't be cycled through and the event shouldn't occur again.
You'll either want to call initChallenge within the outer event binding:
window.addEventListener("load", function() {
// ...
initChallenge();
});
Or, you can use an IIFE with the inner binding:
(function () {
// ...
window.addEventListener("load", initChallenge);
})();
The problem is I need to break the function if it is first time running
is there any function available , or I have to do something like the following?
var times = 1
function abc () {
if (times == 1)
break;
else
.....
times++;
}
times = 0;
Thanks.
You can use this pattern:
function abc() {
if (!abc.flag) {
abc.flag = true;
return;
}
// .. rest of the code
}
It's based on the fact that Function is also an object in Javascript.
Basically this is a Memoization pattern. It has disadvantage that the flag property can be overwritten by another code. The advantage is that you don't need to pollute global scope with additional variables.
thg435 proposed much more elegant solution.
It appears to me that you're trying to solve the problem in the wrong place. Can you tell us the whole story?
In the meantime, something like this should do the trick:
function abc() {
abc = function() {
// ...actual work...
}
}
Details depend on how your function is defined (globally, locally, as a method).
var isFirstTime = true;
function abc () {
if (isFirstTime)
{
isFirstTime = false;
return;
}
.....
}
abc(); //returns
abc(); //runs
var firstTime= true
function abc () {
if (firstTime)
{
firstTime = false;
return;
}
else
{
.....
}
}
Try This :
var times = 1;
function abc () {
if (times == 1){}
else{
.....
times == 0;}
}
I have an input which when im clicking - i want to see alert with '1,2,3,4...' (each press)
<input type='button' value='press' onclick='Clicked();' />
<script>
var t
function Clicked()
{
t=func;
t();
}
function func()
{
var count=0;
return new function () // <=== new or not new ???
{
count++;
alert(count);
}
}
</script>
If im adding the 'new' in the return and click , it says : '1,1,1,1,...'
If im removing the 'new' it doesnt work...
My goal is to use this to get : '1,2,3,4...'
Can someone explain to me what happens ?
You need to use the returned function:
var t = func()
function Clicked() {
t();
}
function func() {
var count=0;
return function () {
count++;
alert(count);
}
}
Example
You have to put the count declaration out of the "func" function and into the global namespace. Like this:
var count=0;
function func() {
count++;
alert(count);
}
You're creating a new var count every time the clickevent fires.. You should place the var count = 0 outside the function as a global variable..
oh and btw, throw out the return stuff please this will work properly:
var count = 0;
function func()
{
count++;
alert(count);
}
And call this method like this: func();
You are getting 1,1,1,1 because you are redefining count every time you call func().
In your case you will need to either put the count variable in the global scope:
var t;
var count = 0;
or change the way you are doing things a little:
var t = 0;
function Clicked(){
t = func(t);
}
function func(count){
count++;
alert(count)
return count;
}
Personally I like the second one. You have less global variables, one less function declaration, and it is cleaner
var t
function Clicked()
{
t=func;
t();
}
var count=0;
function func()
{
return new function () // <=== new or not new ???
{
count++;
alert(count);
}
}