I have a function:
function loremIpsum() {
$('.element').fadeIn()
}
to show a hidden Element - The issue is, that a user can go back with a second button and call the loremIpsum() function again, but the function should be called just once.
Can I limit that in someway ? I couldn't find a Post for that here.
I tried this:
function loremIpsum() {
var executed = false;
return function() {
if (!executed) {
executed = true;
$('.element').fadeOut()
}
}
}
But that didn't work
You can use sessionStorage to keep track of executed boolean value for the session.
function loremIpsum() {
sessionStorage.setItem('executed', true);
$('.element').fadeIn();
}
And in the caller, you can check:
if (!(sessionStorage.getItem('executed') === "true")) { //since sessionStorage stores items as strings
loremIpsum();
}
function loremIpsum() {
loremIpsum= function() {};
$('.element').fadeIn()
}
Did work - nevermind then.
Related
I want to implement a function that takes another function as an argument, and returns a new version of that function that can only be called once.
The first function works, but the 2nd one doesn't work.
Why doesn't the 2nd function work, but can somehow still access the word without a function inside it like the first one?
var logOnce = once(console.log)
function once(fn) {
var call = true;
return function(word) {
if(call) {
call = false;
return fn(word);
}
}
}
function once(fn) {
var call = true;
if (call === true) {
call = false;
return fn;
}
}
logOnce("foo"); ----> "foo"
logOnce("blue"); ----> "blue"
Your second approach doesn't work because it returns the same fn. In fact, it is equivalent to
function once(fn) {
return fn;
}
Therefore, once(console.log) is just console.log, and you can call it as many times as you want.
The first approach works because you return a different function, which will call the original one or not depending on a variable.
I'm relatively new to coding in JavaScript, and I've came across a problem. I like to nest functions to keep things orderly, but how would I exit from a parent function from inside a child function?
example:
function foo1() {
function foo2() {
//return foo1() and foo2()?
}
foo2();
}
See update under the fold
You can't. You can only return from the child function, and then return from the parent function.
I should note that in your example, nothing ever calls foo2 (As of your edit, something does). Let's look at a more real example (and one that comes up a lot): Let's say we want know if an array contains an entry matching some criterion. A first stab might be:
function doesArrayContainEntry(someArray) {
someArray.forEach(function(entry) {
if (entryMatchesCondition(entry)) {
return true; // Yes it does <-- This is wrong
}
});
return false; // No it doesn't
}
You can't directly do that. Instead, you have to return from your anonymous iterator function in a way to stop the forEach loop. Since forEach doesn't offer a way to do that, you use some, which does:
function doesArrayContainEntry(someArray) {
return someArray.some(function(entry) {
if (entryMatchesCondition(entry)) {
return true; // Yes it does
}
});
}
some returns true (and stops looping) if any call to the iterator function returns true; it returns false if no call to the iterator returned true.
Again, that's just one common example.
You've referred to setInterval below, which tells me that you're almost certainly doing this in a browser environment.
If so, your play function almost certainly has already returned by the time you want to do what you're talking about, assuming the game has any interaction with the user other than alert and confirm. This is because of the asynchronous nature of the environment.
For example:
function play() {
var health = 100;
function handleEvent() {
// Handle the event, impacting health
if (health < 0 {
// Here's where you probably wanted to call die()
}
}
hookUpSomeEvent(handleEvent);
}
The thing is, that play will run and return almost immediately. Then the browser waits for the event you hooked up to occur, and if it does, it triggers the code in handleEvent. But play has long-since returned.
Make a note whether the parent function should also return.
function foo1() {
bool shouldReturn = false;
function foo2() {
shouldReturn = true; // put some logic here to tell if foo1() should also return
return;
}
if (shouldReturn) {
return;
} else {
// continue
}
}
It only says that you can't return the parent function in the child function, but we can do a callback and make it happen.
function foo1(cb = () => null) {
function foo2() {
cb();
}
foo2();
}
foo1(() => {
// do something
});
We can use Promises for this:
const fun1 = async () => {
const shouldReturn = await new Promise((resolve, reject) => {
// in-game logic...
resolve(true)
})
if(shouldReturn) return;
}
if you wanna return from the parent function, then just resolve with true
Based on your comment, something like this might work as a main game loop.
function play() {
var stillPlaying = true;
while(stillPlaying) {
... play game ...
stillPlaying = false; // set this when some condition has determined you are done
}
}
I see different topics about the toggle function in jquery, but what is now really the best way to toggle between functions?
Is there maybe some way to do it so i don't have to garbage collect all my toggle scripts?
Some of the examples are:
var first=true;
function toggle() {
if(first) {
first= false;
// function 1
}
else {
first=true;
// function 2
}
}
And
var first=true;
function toggle() {
if(first) {
// function 1
}
else {
// function 2
}
first = !first;
}
And
var first=true;
function toggle() {
(first) ? function_1() : function_2();
first != first;
}
function function_1(){}
function function_2(){}
return an new function
var foo = (function(){
var condition
, body
body = function () {
if(condition){
//thing here
} else {
//other things here
}
}
return body
}())`
Best really depends on the criteria your application demands. This might not be the best way to this is certainly a cute way to do it:
function toggler(a, b) {
var current;
return function() {
current = current === a ? b : a;
current();
}
}
var myToggle = toggler(function_1, function_2);
myToggle(); // executes function_1
myToggle(); // executes function_2
myToggle(); // executes function_1
It's an old question but i'd like to contribute too..
Sometimes in large project i have allot of toggle scripts and use global variables to determine if it is toggled or not. So those variables needs to garbage collect for organizing variables, like if i maybe use the same variable name somehow or things like that
You could try something like this..: (using your first example)
function toggle() {
var self = arguments.callee;
if (self.first === true) {
self.first = false;
// function 1
}
else {
self.first = true;
// function 2
}
}
Without a global variable. I just added the property first to the function scope.
This way can be used the same property name for other toggle functions too.
Warning: arguments.callee is forbidden in 'strict mode'
Otherwise you may directly assign the first property to the function using directly the function name
function toggle() {
if (toggle.first === true) {
toggle.first = false;
// function 1
}
else {
toggle.first = true;
// function 2
}
}
I made code like this, to easier connecting callbacks on events:
dojo.ready(function() {
for(var action in page.actions) {
for(var key in page.actions[action]) {
(function() {
dojo.query(key).connect(action, function(evt) {
if(page.actions[action][key]() == false)
dojo.stopEvent(evt);
});
})();
}
}
});
page = {
actions :
{
onclick :
{
"#page-action-one" : function()
{
alert("Action 1");
return false;
},
"#page-action-two" : function()
{
alert("Action 2");
return false;
}
}
}
};
But click on "#page-action-one" an "#page-action-two" make the same alert("Action 2"). I tried to use cloer, but without effect. I now, I can make it different way, but I would like to now, why is this happening.
You're trying to fix the closure issue by wrapping your event handler assignment in an anonymous function. But the key to that trick is that you have to pass in the looping variable (or variables) as an argument to the anonymous function - otherwise the anonymous function wrapper does nothing. Try:
dojo.ready(function() {
for(var action in page.actions) {
for(var key in page.actions[action]) {
(function(action, key) {
dojo.query(key).connect(action, function(evt) {
if(page.actions[action][key]() == false)
dojo.stopEvent(evt);
});
})(action, key);
}
}
});
This "fixes" the value of action and key at the time the anonymous function is called, so within the anonymous function those variable names only apply to the passed arguments, not to the named variables in the outer scope, which will update on the next loop iteration.
I need to have some functionality in my web app where a specific action occurs when the user clicks and holds on an element. Think of it like the long press on Android.
I have my div:
<div id="myDiv"
onmousedown="press()"
onmouseup="cancel()"
onmouseout="cancel()"
onmousemove="cancel()">Long Click Me</div>
and my javascript:
var down = false;
function press()
{
down = true;
setTimeout(function() { action(); }, 1500);
}
function cancel()
{
down = false; // this doesn't happen when user moves off div while holding mouse down!
}
function action()
{
if (!down)
return; // if the flag is FALSE then do nothing.
alert("Success!");
down = false;
}
This works as long as all I do is press and hold on the element. I have the onmouseout and onmousemove events to call cancel() because I want the user to have the option to change their mind and move the mouse off the element before action() starts.
Unfortunately, it seems that my code does not do this.
In fact, if the use clicks down for a moment, moves the mouse off the div and releases before the 1.5 sec then action() won't bail out as expected.
Edit: Thanks for your input everyone but it turns out I'm just a little bit special and didn't see that I forgot a capital letter in my HTML in my onmouseout. The sample code I gave above should work exactly as expected.
Of course action() is still called. You didn't actually cancel the setTimeout() function. I would suspect that maybe in your real code, you have a scoping issue and maybe aren't testing the same version of the done variable that you think you are.
A better way than using the down flag would be to keep track of the return value from setTimeout() and actually cancel the timer in the cancel() function. Then, action() will never fire when you don't want it to. I think it's also technically a more correct behavior when you mouseout to cancel any chance of the timer firing.
Also, there is no such thing as:
bool down = false;
in javascript. It would have to be:
var down = false;
I would recommend this code:
var downTimer = null;
function down()
{
cancel();
downTimer = setTimeout(function() { action(); }, 1500);
}
function cancel()
{
if (downTimer)
{
clearTimeout(downTimer);
downTimer = null;
}
}
function action()
{
downTimer = null;
alert("Success!");
}
You also need to clear the timeout in your cancel function - otherwise it will still fire - as you initiated it in the down function.
so..
bool down = false;
//your timeout var
var t;
function down()
{
down = true;
t = setTimeout(function() { action(); }, 1500);
}
function cancel()
{
down = false;
clearTimeout(t);
}
function action()
{
if (!down)
return;
alert("Success!");
down = false;
}
There are several things wrong with your code as I see it.
First
bool down = false;
is not valid JavaScript. It should be
var down = false;
Then you have two variables called down: the boolean value and the function. The function will overwrite the variable, until as such time that you execute one of the statements that sets down to true or false.
As others have said: once set, the deferred function will continue to be executed 1.5 seconds later, unless you cancel the timeout. But then again it doesn't matter, since you do check to see if the mouse button is down before doing anything.
So I'd say rename the boolean variable to isMouseDown or something and try again.
to cancel the timeout in the cancel() function, use
var mytimer = null;
function ondown(){mytimer = setTimeOut('action()', 1500;)}
function cancel(){clearTimeout(mytimer);}
function action(){mytimer=null; alert('success!');}
also note that you used down first as a variable end then as a function... Calling if(!down) will always return false because down refers to a function.