Javascript closure and handlers - javascript

I have this javascript function:
function files() {
var dropResult = false;
$('#button1').on('click', function() {
dropResult = true;
});
$('#button2').on('click', function() {
dropResult = false;
});
return dropResult;
}
files();
The dropResult variable must change after we click one of the buttons. How do I write it properly to make my function return the right value of dropResult variable?
I know, that it's about closures but I don't really understand how to fix this problem.
Thanks for help.

I believe you want
var files = (function () {
var dropResult = false;
$('#button1').on('click', function () {
dropResult = true;
});
$('#button2').on('click', function () {
dropResult = false;
});
return function () {
return dropResult;
};
})();
Demo at http://jsfiddle.net/gaby/9b7yK/

var dropResult = false;
$('#button1').on('click', function() {
dropResult = true;
});
$('#button2').on('click', function() {
dropResult = false;
});
function files() {
return dropResult;
}
Assuming all you need is to get the correct value for dropResult, the above code should work.

I will "extend" the answer of Gaby aka, but I think he is totally right. I will make only more specific in private and public methods. and how to access to them, and actually also bind the events to a specific button you can check the fiddle here [http://jsfiddle.net/qsDz6/][1]
HTML
<input type="button" id="button1" value="button 1" />
<input type="button" id="button2" value="button 2">
<input type="button" id="actualValue" value="Actual Value of _dropResult">
JS
var files = (function(__name){
var _name = __name;
var _dropResult = null;
/*Private */
function init(){
eventHandler();
}
function eventHandler(){
$(document).on("click","#button1", $.proxy($r.actionButton1,this));
$(document).on("click","#button2", $.proxy($r.actionButton2,this));
$(document).on("click", "#actualValue", $.proxy($r.dropResult,this));
}
/*Public */
var $r = {}; //will make public any method
$r.actionButton1 = function(){
_dropResult = true;
alert(_dropResult);
}
$r.actionButton2 = function(){
_dropResult = false;
alert(_dropResult);
}
$r.dropResult = function(){alert(_dropResult);}
init();
return $r;
})("files");
Happy coding

Update: Somehow this answer has been down-voted despite the fact that the most up-voted solution was posted at the same time, is equally elegant, and is logically equivalent. The other solution simply chooses to capture the local variable in a function closure rather than an object closure.
The responsibility of being a voter is to actually read and think about what these solutions do, rather than just voting for the answer provided by someone familiar or by the person with the highest reputation.
The responsibility that I have in answering is to only answer questions not for a popularity contest, but when (A) I know for certain a valid answer and am willing to take the time to explain and maintain that answer; or (B) for some discussion questions where there is nothing so clear-cut as the "answer," then only when I have encountered the issue many times in my experience and have something to say about it based on my actual experience.
For that reason, I am leaving my answer up (just as I have done in the past) even when someone in the community anonymously decides to downvote it without any explanation why.
Remember that the answers at Stack Overflow are intended to be a repository of useful solutions to useful questions, for the benefit of all programmers in the future. It is worthwhile to show two different approaches rather than a single one.
Yes, the other solution is elegant and demonstrates nicely capturing a local variable using an anonymous function closure. Yet, in my opinion, my solution is slightly better in the context of the purpose that Stack Overflow has, because this solution can be easily modified into a reusable function for creating many monitoring variables. The other solution would require a bit of deconvolution in order to make it useful for more than a single static instantiation of one monitoring function.
function files() {
var dropResult = {};
$('#button1').on('click', function() {
dropResult.result = true;
});
$('#button2').on('click', function() {
dropResult.result = false;
});
return dropResult;
}
var dropObject = files();
The variable dropObject is a "monitoring variable" that can be used anywhere in order to check the status of what you are monitoring (in this case, which alternative the user last specified by their most recent click on either button1 or button2.)
In code that uses the result from files() you can do this
if (dropObject.result) {
/* do something here that you want to do when the result is true */
} else {
/* do something here when the result is false */
}
I would suggest storing something more meaningful than true or false (what if you wanted to add a third button and then monitor which of the three had last been clicked, for example?).
Note: Here is how I would write a smaller, more efficient reusable monitoring function for my use (not hard-wiring any parameters or names inside the function) and apply it to this scenario:
function clickMonitor(ids) {
var i, f = function() { i = this; }; ids = ids.match(/(\S+)/g) || [];
for (i=0; i<ids.length; i++)
document.getElementById(ids[i]).onclick = f;
return function() { return i; };
}
This next part just creates a dropResult variable that would be
"plug and play" in place of your dropResult variable, except that you
would have to check to see if dropResult() is true or false
(function invocation) rather than just dropResult.
dropResult = (function() {
var x = clickMonitor('button1 button2');
return function() { return x().id == 'button1'; };
})();
In general, this is how you would use it (more than two button IDs can be passed to it, of course, if wanted):
getMostRecentClickedButton = clickMonitor('button1 button2');
Calling getMostRecentClickedButton() returns the entire button
object most recently clicked so that you can do something with it, like
make the font bold, etc., without needing to perform another intermediate
jQuery or JavaScript procedure.

I don't understand the need for this but one way would be
function files() {
files dropResult = false;
return files.dropResult;
}
$(document).on('click', '#button1', function() {
files.dropResult = true;
});
$(document).on('click', '#button2', function() {
files.dropResult = false;
});
files();

Related

Can you alter a statement in a javascript function after is run once

I'm having a hard time figuring this out. I'd like the xxp.run.pause(); to be replaced by xxp.run.play(); after the initial code below is actioned by a user once. I've tried creating a closure but I'm not sure I set it up right. Any help would be very much appreciated.
doSkip: function() {
XXP.run.removeListener('canper', XXP.Skip);
XXP.run.currentTime = XXP.skipTo;
XXP.run.pause(); // this is what I would like to change
}
You may set a flag somewhere which records whether or not the doSkip function has been called before:
var hasSkip = false;
doSkip: function() {
XXP.run.removeListener('canper', XXP.Skip);
XXP.run.currentTime = XXP.skipTo;
if (!hasSkip) {
XXP.run.pause();
hasSkip = true;
}
else {
XXP.run.play();
}
}
You can wrap the function in an IIFE with a persistent variable that checks to see if it's been paused. This has the advantage over having a separate variable elsewhere because hasPausedOnce is only needed for the doSkip function - no need to populate the outer scope (which can have readers of your code worrying about whether hasPausedOnce is going to be altered elsewhere)
doSkip: (() => {
let hasPausedOnce = false;
return function() {
XXP.run.removeListener('canper', XXP.Skip);
XXP.run.currentTime = XXP.skipTo;
if (!hasPausedOnce) {
XXP.run.pause();
hasPausedOnce = true;
} else XXP.run.play();
};
})()

Getting correct scope in functions (not using that = this)

I am trying to fix a function I have here to be able to use it without using a that = this (or self = this as some like to use). It is a scoping issue but I am not sure how to get around it, and I would like to get in the habit of not using a that = this . So the functions are all in a return (angular factory) and I am having trouble referencing another function . Let me show you what I mean :
return {
loadStates: function() {
var that = this;
//chgeck if is loaded module, then change and fire callback
var currentModules = moduleHolder.getModules();
if (currentModules[name]) {
//works here
this.prepState();
} else {
//module cannot be found check for 5 seconds
$log.warn("Requesting " + name + "...");
var timeToCheck = true;
setTimeout(function() {
timeToCheck = false;
}, 5000);
var check = {
init: function() {
check.checkAgain();
},
checkAgain: function() {
if (timeToCheck) {
if (currentModules[name]) {
//but not here
that.prepState();
} else {
//still doesn't exists
setTimeout(check.checkAgain, 200);
}
} else {
//doesn't exist after 5 seconds
$log.error("Requested module (" + name + ") could not be found at this time.");
}
}
};
check.init();
}
},
prepState: function() {
}
}
So in the top if it finds the currentModule[name] I can use a this.prepState() and it works fine. However inside the timing functions I cannot use the this anything because it is inside a different scope so I have temporarily gotten around this by setting a that = this up top, however I would like see if I could not use this method. How does one get around this without using the that= this? Thanks!
It is a scoping issue...
No, it isn't. this and scope have essentially nothing to do with each other. (For now; ES6's arrow functions will change that.) It's an issue of how the functions are called.
If you pass a function reference to something that will call it later, unless the thing you're passing it to has a way you can use to tell it what to use for this when calling it, your function will get called with this not referring to what you want it to refer to.
You can get a new function reference that will call your original function with the correct this by using Function#bind:
var usesCorrectThis = originalFunction.bind(valueForThis);
So for example, suppose I have:
var check = {
name: "Fred",
sayHello: function() {
console.log("Hi, I'm " + this.name);
}
};
If I do:
check.sayHello();
All is good: Calling the function as part of an expression retrieving it from a property tells the JavaScript engine to use the object as this during the call.
However, if I do:
setTimeout(check.sayHello, 0);
...that doesn't work right, because when setTimeout calls the function, it doesn't use the right value for this.
So I can use Function#bind to address that:
setTimeout(check.sayHello.bind(check), 0);
More (on my blog):
Mythical methods
You must remember this
there are different ways you can do that.
One way is to use bind function.you can use
var checkInitBindFn = check.init.bind(this);
checkInitBindFn();
Secondly you can use call and apply also.
check.init.call(this);
check.init.apply(this);
Like this you can use this instead of that.
Check the complete api doc online...
It's not a scoping issue. If you want to avoid self = this you can always reference functions by objects. Makes cleaner code and since factories in angular are singletons you're not wasting memory.
angular.module('myApp').factory('myFactory', function ($timeout) {
var myFactory = {
loadState: function () {
$timeout(function () {
myFactory.check();
}, 500);
},
check: function () {
},
};
return myFactory;
});

efficiently creating variables when a checkbox is checked and using these variables later in the code

below is the information I need help with.
$(document).ready(function(){
$('.checkboxes :checkbox').click(function(){
if($(this).is(':checked')){
console.log(this.id + this.checked)
i want to set a variable with the samename of the id of the checked box
so if showItems was checked i would have a variable
var showItems = true;
I want this so I could see if showItems is checked which would alow me to perform the proper functions
i think i could do something like this
if($this.id = "withones"){
var withones = true;//on
}
if($this.id = "withoutOnes"){
var withoutOnes = true;//on
}
etc.
i feel like the above is a rookie way to code. lets say i have alot of checkboxes and it also looks like im repeating myself. I tried putting the ids in an array and loop through them but I got the html element in the console when i clicked on the box. I would like for someone to tell me if there is a more efficient way to set up these variables. and if so show me please.
Also I'm new to programming so thanks for your help so far. but I was also thinking about another problem. if I set up these variables here and I want to set up another function somewhere else to perform mathematical operations perse. i want that function to be able to evaluate the value of the withones and withoutOnes variables so I would like to do something like this in the function
function add(){
if(withones){ //true|| false
return 2 + 2;
}
if (withoutOnes) {
return 'blah'
};
}
I have had problems in the past trying to test the values that are set outside the function. I think i tried setting it in the arguments. but it just didn't read. If you could also show me an example of using the variables some where else in the code like discussed above that will be helpful . I forgot to mention that the value of the variable will change when the user clicks on the box. either to true or false. I think my problem in the past is that when the box is checked and then uncheck I had a problem changing the variable especially when it is being used in a separate function
}
});
});
You can have an object with your vars and add vars to that object dinamically:
var oVars = {}
// adding a var
oVars[nameVar] = valueVar
// accessing the var
oVars[nameVar]
You can capture the id with the attr() or you can just change the value of the checkbox with val() method in jQuery like this: FIDDLE
$(document).ready(function () {
$('.checkboxes').change(function (event) {
if ($(this).is(':checked')) {
var captureId = $(this).attr('id');
$(this).val(true);
alert($(this).val());
}
else {$(this).val(false);
alert($(this).val());}
});
});
Note that you can evaluate later all the checkboxes with one button and collect the value false or true from them. Why would you go through all of the complications with changing values of variables.
The other two answers are correct, though it sounds like you're wanting to know generally how to manage a big list of checkboxes with differing methods depending on type. It could look like this:
function multiply(this_object){
if((this_object.is(':checked')) && (this_object.attr("with") == 1))
return "with withone and checked";
else
return "is not both";
}
$(document).ready(function(){
$('.checkboxes').click(function(){
var this_object = $(this);
alert(multiply(this_object));
});
});
There should be no need to store all of the values in a variable unless you are passing all of them to another page - eg., via AJAX. Just reference them straight from the source field. If you need other info stored alongside, make a new attribute on the field - like the "with" one that I made for this example. See this Fiddle: http://jsfiddle.net/6ug6gL97/
your question is quite broad; so I’ll try to do my best to give you some kind of answer. First of all I’d use variables of global scope when declaring variables: withones and withoutOnes. Secondly, you wanted to avoid repetition in your code. Well, for that purpose I’d use JavaScript Arrays. In an array, you can add your variables as objects. In an object you can have your ids and other data “packed” neatly in the array, which in turn helps your code to become efficient.
Below is an array with objects:
objectArray = [{
id: "withones",
checked: false,
method: function () {
return 2 + 2;
}
}, {
id: "withoutOnes",
checked: false,
method: function () {
return 'blah';
}
}];
The above array can be used in your $('.checkboxes :checkbox').click(function() handler and add() function to avoid repetition. The updated code is below where jQuery's each() method is used for looping Array elements.
The last a bit of your question was related to add() function. Well, this was the tricky bit of your question, and I tried to use a callback function hopefully in the right way to execute your functions from the array. In the add method I tried to follow this answer: https://stackoverflow.com/a/13343452/2048391
About the last bit I’m not 100% sure did I use a callback function in the right way; so I hope someone more familiar with these tricky JavaScript functions can correct me, if something needs to be changed –thanks.
objectArray = [{
id: "withones",
checked: false,
method: function () {
return 2 + 2;
}
}, {
id: "withoutOnes",
checked: false,
method: function () {
return 'blah';
}
}];
$(document).ready(function () {
$('.checkboxes :checkbox').click(function () {
var id = this.id;
var checkedValue = this.checked;
$.each(objectArray, function (index, object) {
if (object.id === id) {
object.checked = checkedValue;
}
});
add();
});
function add() {
// clear results
$("#addResults").text("");
$.each(objectArray, function (index, object) {
if (object.checked === true) {
var returnValue = createCallback(object.method)
$("#addResults").append(returnValue + "<br>");
console.log(returnValue);
}
});
}
function createCallback(method) {
return method();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="checkboxes">
<input type="checkbox" id="withones"></input>
<label>With Ones</label>
<br>
<input type="checkbox" id="withoutOnes"></input>
<label>Without Ones</label>
</div>
<div id="addResults">
</div>

need help understanding closures usage in this code

Here is a simplified snippet from some code I wrote for managing tablet gestures on canvas elements
first a function that accepts an element and a dictionary of callbacks and register the events plus adding other features like 'hold' gestures:
function registerStageGestures(stage, callbacks, recieverArg) {
stage.inhold = false;
stage.timer = null;
var touchduration = 1000;
var reciever = recieverArg || window;
stage.onLongTouch = function(e) {
if (stage.timer) clearTimeout(stage.timer);
stage.inhold = true;
if (callbacks.touchholdstart) callbacks.touchholdstart.call(reciever, e);
};
stage.getContent().addEventListener('touchstart', function(e) {
e.preventDefault();
calcTouchEventData(e);
stage.timer = setTimeout(function() {
stage.onLongTouch(e);
}, touchduration);
if (callbacks.touchstart) callbacks.touchholdstart.call(reciever, e);
});
stage.getContent().addEventListener('touchmove', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdmove) callbacks.touchholdmove.call(reciever, e);
} else {
if (callbacks.touchmove) callbacks.touchmove.call(reciever, e);
}
});
stage.getContent().addEventListener('touchend', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdend) callbacks.touchholdend.call(reciever, e);
} else {
if (callbacks.touchend) callbacks.touchend.call(reciever, e);
}
stage.inhold = false;
});
}
later I call registerStageGestures on a few elements (represented by 'View' objects) in the same page. Something like:
function View() {
var self=this;
..
function InitView() {
...
registerStageGestures(kineticStage, {
touchstart: function(e) {
// do something
},
touchmove: function(e) {
// do something
},
touchendunction(e) {
// do something
},
touchholdstart: function(e) {
// do something
},
touchholdmove: function(e) {
// do something
},
touchholdend: function(e) {
// do something
},
}, self);
Everything works fine, however I'm left wondering about two things in the implementation of registerStageGestures:
First, is it necessary to make inhold, timer and onLongTouch members of the stage ? or will closures make everything works well if they are local vars in registerStageGestures ?
Second, is it necessary to call the callbacks with '.call(receiver,' syntax ? I'm doing this to make sure the callback code will run in the context of the View but I'm not sure if it's needed ?
any input is much appreciated
Thanks!
First, is it necessary to make inhold, timer and onLongTouch members
of the stage ? or will closures make everything works well if they are
local vars in registerStageGestures ?
As far as registerStageGestures() is concerned, var inhold, var timer and function onLongTouch(e) {...}. would suffice. The mechanism by which an inner function has automatic access to its outer function's members is known as "closure". You would only need to set stage.inhold, stage.timer and stage.onLongTouch if some other piece of code needs access to these settings as properties of stage.
Second, is it necessary to call the callbacks with '.call(receiver,'
syntax ? I'm doing this to make sure the callback code will run in the
context of the View but I'm not sure if it's needed ?
Possibly, depending on how those callbacks are written. .call() and .apply() are sometimes used when calling functions that use this internally. In both cases, the first parameter passed defines the object to be interpreted as this. Thus, javascript gives you the means of defining general purpose methods with no a priori assumption about the object to which those methods will apply when called. Similarly, you can call a method of an object in such a way that it acts on another object.
EDIT:
For completeness, please note that even in the absence of this in a function, .apply() can be very useful as it allows multiple parameters to be specified as elements of a single array, eg the ubiquitous jQuery.when.apply(null, arrayOfPromises)...
There are some simple answers, here.
First, closure:
Closure basically says that whatever is defined inside of a function, has access to the rest of that function's contents.
And all of those contents are guaranteed to stay alive (out of the trash), until there are no more objects left, which ere created inside.
A simple test:
var testClosure = function () {
var name = "Bob",
recallName = function () { return name; };
return { getName : recallName };
};
var test = testClosure();
console.log(test.getName()); // Bob
So anything that was created inside can be accessed by any function which was also created inside (or created inside of a function created in a function[, ...], inside).
var closure_2x = function () {
var name = "Bob",
innerScope = function () {
console.log(name);
return function () {
console.log("Still " + name);
}
};
return innerScope;
};
var inner_func = closure_2x();
var even_deeper = inner_func(); // "Bob"
even_deeper(); // "Still Bob"
This applies not only to variables/objects/functions created inside, but also to function arguments passed inside.
The arguments have no access to the inner-workings(unless passed to methods/callbacks), but the inner-workings will remember the arguments.
So as long as your functions are being created in the same scope as your values (or a child-scope), there's access.
.call is trickier.
You know what it does (replaces this inside of the function with the object you pass it)...
...but why and when, in this case are harder.
var Person = function (name, age) {
this.age = age;
this.getAge = function () {
return this.age;
};
};
var bob = new Person("Bob", 32);
This looks pretty normal.
Honestly, this could look a lot like Java or C# with a couple of tweaks.
bob.getAge(); // 32
Works like Java or C#, too.
doSomething.then(bob.getAge);
? Buh ?
We've now passed Bob's method into a function, as a function, all by itself.
var doug = { age : 28 };
doug.getAge = bob.getAge;
Now we've given doug a reference to directly use bobs methid -- not a copy, but a pointer to the actual method.
doug.getAge(); // 28
Well, that's odd.
What about what came out of passing it in as a callback?
var test = bob.getAge;
test(); // undefined
The reason for this, is, as you said, about context...
But the specific reason is because this inside of a function in JS isn't pre-compiled, or stored...
this is worked out on the fly, every time the function is called.
If you call
obj.method();
this === obj;
If you call
a.b.c.d();
this === a.b.c;
If you call
var test = bob.getAge;
test();
...?
this is equal to window.
In "strict mode" this doesn't happen (you get errors really quickly).
test.call(bob); //32
Balance restored!
Mostly...
There are still a few catches.
var outerScope = function () {
console.log(this.age);
var inner = function () {
console.log("Still " + this.age);
};
inner();
};
outerScope.call(bob);
// "32"
// "Still undefined"
This makes sense, when you think about it...
We know that if a function figures out this at the moment it's called -- scope has nothing to do with it...
...and we didn't add inner to an object...
this.inner = inner;
this.inner();
would have worked just fine (but now you just messed with an external object)...
So inner saw this as window.
The solution would either be to use .call, or .apply, or to use function-scoping and/or closure
var person = this,
inner = function () { console.log(person.age); };
The rabbit hole goes deeper, but my phone is dying...

Calling functions in two different ways - JavaScript

I'm very new to JavaScript, so my apologies if this answer is glaringly obvious or I'm barking up the wrong tree!
What's the difference in the following code snippets:
function primeAddNum(innerHTML) {
return function() {
addNum(innerHTML);
return false;
};
}
var func = primeAddNum(innerHTML);
The second one:
var func = function() {
return function() {
addNum(innerHTML);
return false;
};
}();
The top one works the way I'd like it to, but not the bottom, but that's not overly important to me. What I want to know is the logic behind each block, because I just can't see the difference!
The problem with the second block is that innerHTML is undefined there, since you're not passing it. They will become equivalent if you change it to:
var func = function(innerHTML) {
return function() {
addNum(innerHTML);
return false;
};
}(innerHTML);
Well with the second one you can only create a func once. But with first one, you can create many:
var func1 = primeAddNum(innerHTML);
var func2 = primeAddNum(someOtherInnerHTML);
there is no difference, you can use both without any problems

Categories

Resources