This is another Javascript closure question. I run the following code as soon as the document loads:
var handlers = (function () {
var clickHandler = function() { alert ('click!'); }
return {
clickHandler : clickHandler
}
}());
$('#element').addEventListener('click', handlers.clickHandler);
Then at some later point I want to replace the functionality of the handler and thus do something like:
handlers.clickHandler = function() { alert ('changed handler!'); }
From my understand of Javascript closures the event listener should keep a reference of the clickHandler function, and thus the functionality should change accordingly. Yet, this is not what happens. The event listener triggers the initial function. I have managed to achieve the result I want using eval but this feels like a hack. Is there a legitimate way to do what I want?
$('#element').on('click', /*the solution: */ () => handlers.clickHandler());
You need to resolve the identifier on execution of the handler, not on registration. That can be done by wrapping the call into a function, like i did above ( with an arrow function).
Related
I am having trouble understanding why the function parameter of the event listener isn't accepting just the function. Here's the code:
Variables are declared:
var spanJS = document.getElementById("spanJS")
var txtPlayers = document.getElementById("ContentPlaceHolder1_txtPlayers")
var txtAmount = document.getElementById("ContentPlaceHolder1_txtAmount")
Then associate the event listeners:
txtAmount.addEventListener("keyup", UpdateTotals())
txtPlayers.addEventListener("keyup", UpdateTotals())
Then the function:
function UpdateTotals() {
...
}
This is the whole code. The problem is, when i run it, it executes UpdateTotals() without any keyup event, and the listeners don't work.
If i do the following change, it works like intended:
txtAmount.addEventListener("keyup", function () {
UpdateTotals()
})
txtPlayers.addEventListener("keyup", function () {
UpdateTotals()
})
Can anyone explain me why i can't just put the function's name, i have to "child" it in another function?
You need to change the event listeners by removing the () at the end of the handler names, like so:
txtAmount.addEventListener("keyup", UpdateTotals);
This is to pass the reference of the function UpdateTotals, and not run the function UpdateTotals(). The latter will actually run the function immediately, and pass in the return value of the function.
See this link about the idea of JavaScript function references (without parentheses).
In Javascript, UpdateTotals() is the value of the function when called without passing arguments, while UpdateTotals is the function itself
So you want:
txtAmount.addEventListener("keyup", UpdateTotals)
txtPlayers.addEventListener("keyup", UpdateTotals)
You don't need the parentheses within the event listeners.
Change:
txtAmount.addEventListener("keyup", UpdateTotals())
txtPlayers.addEventListener("keyup", UpdateTotals())
to:
txtAmount.addEventListener("keyup", UpdateTotals)
txtPlayers.addEventListener("keyup", UpdateTotals)
today my question is asking how I would access a function inside a function. So, for example, I have a button, and if I click it, it would alert. The thing is, if you have a function surrounding the function, the inside function with the alert would not alert.
Here's an example:
html:
<button onclick="doStuff()">Alert</button>
js:
function nothing() {
var doStuff = function() {
alert("This worked!")
}
}
so the doStuff() function would not work. Can someone help me find a way to access it?
#Joseph the Dreamer is ultimately correct, but if you were dead set on calling a function that's nested in another function you could use an OOP approach.
Create a javascript "class" object and scope your function to "this":
function Nothing() {
this.doStuff = function() {
alert("works");
}
}
Next you add an id to your button,
along with a click event listener
Then, inside your click event you can call doStuff within the Nothing "Class" function like this:
var object = new Nothing();
object.doStuff();
https://jsfiddle.net/me7fek5f/
You can't. That's because it's enclosed in a scope that you can't really access globally. The only way you can access it is to expose it somewhere outside nothing.
Is this a homework question?
You're probably asked to do something like this:
function nothing() {
var doStuff = function() {
alert("This worked!")
}
var yourButton = getYourButton();
attachClickListener(yourButton, doStuff);
The implementations of getYourButton and attachClickListener are left to the reader.
I'm learning to develop Windows 8 style applications with the help of a book. The chapter I'm reading focuses on HTML, CSS and JavaScript languages for developing. The application displays in a ListView the images you have in the My Pictures Folder and deletes them when the user clicks or taps an image. Here is the code that implements the deletion of an image in the ListView:
var lv = document.getElementById('lv');
lv.addEventListener('iteminvoked', function (eventObj) {
eventObj.detail.itemPromise.then(function (listViewItem) {
var binding = files.dataSource.createListBinding();
binding.fromIndex(listViewItem.index).then(function (dataItem) {
var key = dataItem.key;
files.dataSource.remove(key);
binding.release();
});
});
});
My question is, where does the eventObj parameter of the anonymous function in the addEventListener method gets its value? I have found a similar question asked here: Passing arguments in anonymous functions in JavaScript, but i cannot fully understand it. I searched the documentation for addEventListener on MSDN but it just says it takes an event handler function, but it doesn't say anything about the parameters. Thanks in advance.
It's rather simple: whatever function internally calls that callback passes the arguments. See, addEventListener tells the executing Javascript engine to call the callback function you specify whenever an event occurs. The javascript engine saves your anonymous function in some variable - and cann call it later on using that exact variable, passing any number of arguments.
To illustrate it, consider something like this the internal function that handels events (purlely fictional, just to illustrate how it could be done):
var callbacks = [];
function addEventListener(newEvent, newCallback) {
callbacks.push({event : newEvent, callback : newCallback});
}
function handleEvent (someEvent) {
for (var i = 0 ; i < callbacks.length ; i++ ) {
if (callbacks[i].event == someEvent.name) {
callbacks[i].callback(someEvent);
}
}
}
Some more explanation:
As javascript is a so-called "functional language", functions are just values of variables.
function someFunc () {}
is actually just some kind of shortcut (technically it's not, but it does the same thing) for
var someFunc = function () {}
This having said, it's of cours possible to associate multiple names with one function:
var someFunc = function () {}
var sameFunc = someFunc;
var stillSame = somefunc;
var alsoSame = stillSame;
and you can call that function using any of those names, including passing arguments of course:
var someFunc = function (arg) { alert(arg); }
var sameFunc = someFunc;
sameFunc("It worx");
You can even call a function without ever naming it:
(function () {alert("test")})();<
or
(function (arg) { alert(arg); })("test")
Using this concept to perversion finally leads (long way to go however) to things like the y-combinator.
Event handlers may be attached to various objects including DOM
elements, document, the window object, etc. When an event occurs, an
event object is created and passed sequentially to the event
listeners.
Source: https://developer.mozilla.org/en-US/docs/Web/API/Event
An event listener or event handler can be an anonymous function or named function, it really doesn’t matter. The point is that it’s the event interface that defines the event object that is passed to the handler.
To find out exactly the event property from the event you are using, please refer to the windows docs: http://msdn.microsoft.com/en-us/library/windows/apps/br211827.aspx
The arguments recieved by the event listener are sent from the dispatchEvent, i.e. when the event dispatched it passes an event object to your handler.
Refer to this documentation on how to create and dispatch the event. The event object can vary in structure to convey information to the eventhandler to execute necessary steps. So in your case when you do lv.dispatchEvent(newevent) this sends an newevent as eventObj to your event handler.
Keep in mind there can be multiple eventhandlers listening to an event so the browser maintains a stack for the eventlisteners running them sequentially with each of them passed eventObj.
Anonymous function is no different from a named function. In JavaScript functions are first-class objects meaning regular objects. So you can pass them like regular objects(numbers,strings) without having to name them. Only thing is reuse becomes an issue.
What you need to understand this code is to rewrite it a bit:
var lv = document.getElementById('lv'),
invokeHandler = function (eventObj) {
var promiseFullfilled = function (listViewItem) {
var binding = files.dataSource.createListBinding(),
anotherPromiseFullfilled = function (dataItem) {
var key = dataItem.key;
files.dataSource.remove(key);
binding.release();
};
binding.fromIndex(listViewItem.index).then(anotherPromiseFullfilled);
};
eventObj.detail.itemPromise.then(promiseFullfilled);
};
lv.addEventListener('iteminvoked', invokeHandler);
This code works just the same, however it is now obvious that addEventListener or then actually do not know anything about the callback functions they are passed with. They can, however, use Function.prototype.call or Function.prototype.apply to apply arguments:
// This is PSEUDOCODE, event model actually works in a totally different way
HTMLElement.prototype.addEventListener = function(eventType, callback, bubbles) {
// callbacks is some internal collection for this specific element, probably available via a closure, looks something like:
// {
// 'someEventType': [callback1, callback2],
// 'someOtherEvent': [callback1, callback3, callback4]
// }
callbacks[eventType].push(callback);
}
// This is called whenever an event is triggered on an element
HTMLElement.prototype.dispatchEvent = function(event) {
callbacks[event.type].forEach( function(callback) {
return callback.call(this, event); // the callback is called with 'this' set to the element DOM object, and 'event' is the first argument
});
// then it can bubble or cancel depending on the event type and callback results
}
it is a CustomEvent, and all the process is like that:
//you add a anonymous function to a specific listener
lv.addEventListener('iteminvoked', function (eventObj) {
console.log(eventObj===myEvent);
});
//somewhere in your code a CustomEvent gets created based on "iteminvoked" key
var myEvent = new CustomEvent("iteminvoked", {
itemInfo: {
name: "yourItem"
},
bubbles: true,
cancelable: false
});
//somewhere when an item gets invoked this code raise the `iteminvoked` trigger
lv.dispatchEvent(myEvent);
all the functions that are passed as a listener are stored based on the key, something like:
var observers = {
"iteminvoked" : [f1, f2],
//other keys
}
it doesn't have anything to do with not having name, the function object is stored in the some kind of array. and dispatchEvent goes thru the array and invokes all the functions, and pass the myEvent as their parameter. It is a Observer pattern, implemented in javascript, I have implemented it once in my own javascript library like:
var lv = /*your element*/;
if(observers["iteminvoked"]){
for(var i=0;i<observables["iteminvoked"].length;i++){
var func = observables["iteminvoked"][i];
var o = func.call(lv, myEvent);
//this line is to support return false
if(o!==undefined && o===false) break;
}
}
as you can see it is dispatchEvent resplonsiblity to invoke all the observers, and your function no matter it has name or not gets invoked with the lv as the this context and myEvent as the parameter.
I was trying the following:
f.addEventListener('submit',(function(frm){
var func = (function(e){somefunction(e,frm);})(e);
})(f),false);
But this is failing. I want to pass the form (f) as a static reference and the dynamic event object to the named function 'somefunction'.
What I have above isnt working, what is the right syntax for passing both?
The issue is that each of the functions is being called right away, with undefined actually being passed to addEventListener().
You'll want to instead return one of the functions without its calling parenthesis so the event can call it later:
f.addEventListener('submit', (function (frm) {
return function (e) {
someFunction(e, frm);
};
})(f), false);
Though, with event bindings, you may not necessarily need the closure, as the <form> will be the context (this) of the function passed:
f.addEventListener('submit', someFunction, false);
function someFunction(e) {
var frm = this;
// ...
}
not saure exactly what you are trying to do but, to looks like you are trying to manually pass in the form via the event handler. Instead save a reference and just refer to it in the handler such as
f.addEventListener('submit',function(){
var func = function(e){
somefunction(e,f);
};
},false);
you shouldn't need the self executing functions unless I am missing your intent here
window.onload = function() {
document.getElementById('clickMe').onclick = runTheExample;
}
function runTheExample() {
alert('running the example');
}
This is a simple event handler for the onclick event for an html input button with id = clickMe.
In line 2, why is the call to function runTheExample not immediately followed by ()? I thought that to call a function you must pass it any variables/objects it expects in an open/close parenthesis, and if the function isn't expecting anything, you must still include the open and close parenthesis like runTheExample().
document.getElementById('clickMe').onclick = runTheExample;
The intention here is not to call runTheExample() but to assign the reference to the function runTheExample to the onclick event.
Internally, when the onclick event is fired, Javascript is able to call the function runTheExample through the reference you provided on the code above.
Snippet
var myFunction = function() { return 42; };
// Assigning the reference
myObject.callback = myFunction;
myObject.callback(); // Has the same effect as calling myFunction();
// Assigning by calling the function
myObject.callback = myFunction();
myObject.callback; // Returns 42
myObject.callback(); // Exception! Cannot call "42();"
That's not Javascript-specific. Passing functions by reference is available in many languages.
You use the parenthesis only to invoke (call) a function. When you're assigning it to onclick, you're merely passing it by reference.
To better understand this, think about the other method of declaring a function:
var runTheExample = function () {
alert('running the example');
}
Regardless of what method you use, runTheExample will contain a reference to the function (there are some differences, like the function reference not being available before assignment, but that's a different story).
Functions are objects in javascript. That line sets the onclick property of the click me element to the runTheExample function, it doesn't call that function right then.
var a =runTheExample; //sets a to runTheExample
a(); //runs the runTheExample function
So when the function name is referenced without the () it is referring to the function object, when you add the () it is a call to the function, and the function executes.
It's not calling it, but rather setting the property onclick. When a call is made to onclick(), it will then run the function you've defined. Note however that the context of this will be the object that calls it (document.getElementById('clickMe')).
You're not calling the function here. You're setting the function as an event handler, and the function is not actually called called until the event is fired. What you've written references the function; that's a different notion than actually calling it.
In this case, the runTheExample function is being treated as a variable and being assigned to the onclick event handler. You use () after a function name to call a function. If you added them here, what would happen is that runTheExample() would be called once during load, showing an alert, and then a null value would be assigned to the onclick handler.
Because it binds runTheExample to onclick event.
When you add () it triggers the function.