Here is a script that looks at the links that exist on a page and binds a mousedown event listener to each link. When a mousedown event is triggered it calls a function that creates an alert with the link's href. In IE9+, this works fine, but in IE8, this is undefined.
<html>
<body>
test
<script>
var c=function(){alert(this.href)};
var a=document.getElementsByTagName("a");
for(var b=0; b<a.length; b++) {
if (a[b].addEventListener) {
a[b].addEventListener("mousedown",c,false);
} else {
a[b].attachEvent("onmousedown",c);
}
}
</script>
</body>
</html>
I've tried adding this and this.href as arguments to the function, but it doesn't look like those functions accept arguments. Anyone know how I would get this to work?
Try this:
var c = function (e) {
e = e || event; // if e is not available, use global event object
var target = e.target || e.srcElement; // some browsers use target to refer to event target, and some srcElement
alert(target.href);
};
I think IE8 uses a global event object, instead of sending parameter in callback function.
Unfortunately, in the IE event model, listeners attached using attachEvent do not have their this set to the calling element so it defaults to window (i.e. the global object).
So instead of:
a[b].attachEvent("onmousedown",c);
you can ensure this is set to the element using:
a[b].attachEvent("onmousedown",(function(fn, el) {
return function() {fn.call(el, event)};
}(c, a[b]));
Look for examples of "addEvent" function, there are many around that fix this issue.
Related
Callback method is not being called when I attach my event to element. The method in question belongs to an object but it seems the way I am calling it the method isn't being called when the click event occurs.
var myObject = {
handledrop : function () {
//retrieved created html element
var elem = document.getElementById("required");
elem.addEventListener("click", this.deleteFavorite.bind(this), false);
},
//this method isn't being called when click event occurs
deleteFavorite: function (evt) {
console.log(evt);
}
}
What am I doing wrong? How do I pass the right context so that the correct method is called and passed the right context which is event
Couple of debug/trouble-shooting tips:
Post the html for the "required" element.
Check that the "required" element you think you're getting is valid:
var elem = document.getElementById("required");
console.log('elem:',elem);
You can also iterate its properties to ensure that function exists:
foreach(var property in elem){
console.log('property:',property);
}
For cross browser support - you might want to read this post:
addEventListener vs onclick
How can I use "this" in this case?
I got an error.. The page can't set display at null or undefined.
<button onclick="myFunction(this)">
<script>
function myFunction() {
this.style.display='none';
}
</script>
You can use func.call to bind a context for that function invocation (otherwise in your case it will be pointing the the global object (window) ):
myFunction.call(this);
or with myFunction(this)
You should do:
function myFunction(elm) {
elm.style.display='none';
}
An even better idea is to register the click event using addEventListener instead of with onclick inline in the HTML:
var theButton = document.getElementById("theButton");
theButton.addEventListener("click", function(e) {
var originalElement = e.srcElement || e.originalTarget;
originalElement.style.display = 'none';
});
Of course, you'll need to either give the button the same id I did -- theButton -- or otherwise retrieve it, but this is a much more flexible and modern way to handle the event.
What's a standard way of associating unique properties to anonymous JavaScript functions while creating them so that these properties can be accessed within the functions themselves when they are executed (i.e. run time)?
A scenario is this:
Say I have events which I want to bind to dynamically generated anonymous functions.
var events = ['connect','disconnect','error','connect_failed'];
for(a in events){
var handler = function(){
// console.log(arguments.callee.custom); // Not reliable 'cos callee is supposedly deprecated
console.log('<event-name>');
};
handler.custom = events[a];
$(window).on(events[a],handler);
}
Since using arguments.callee is deprecated and not guaranteed to be optimal on all platforms. What's the recommended way of achieving something similar to this?
You can use handler.custom in your function, too:
var handler = function() {
console.log(handler.custom);
console.log('<event-name>');
};
To prevent scoping issues in case of asynchronous callbacks, you can create a newly scoped handler function by wrapping your code in a closure:
for(a in events){
(function() {
var handler = function(){
console.log(handler.custom);
console.log('<event-name>');
};
handler.custom = events[a];
$(window).on(events[a],handler);
})();
}
EDIT: just realized you can use forEach as well (although that also suffers from browser compatibility issues):
events.forEach(function(event) {
var handler = function() {
...
};
handler.custom = event;
$(window).on(event,handler);
});
Named function expressions give a reference to the function itself only within the function scope:
var events = ['connect', 'disconnect', 'error', 'connect_failed'];
for (var a in events) {
var handler = function inside() {
console.log(inside.custom); // not deprecated
console.log('<event-name>');
};
handler.custom = events[a]; // now will stay with function even if renamed or moved
$(window).on(events[a], handler);
}
However, Internet Explorer 8 and below will not parse named functions correctly - Juriy Zaytsev explains the exact issue behind them in more detail: http://kangax.github.io/nfe/#named-expr
If you really have to target IE8 and below, either stick with arguments.callee or use conditional compilation for IE, which is basically IE conditional comments for JavaScript.
You could do something like this:
var events = ['connect','disconnect','error','connect_failed'];
function assignHandler(eventType, custom) {
$(window).on(events[a], function() {
console.log(custom);
});
}
for(a in events){
assignHandler(events[a], events[a]);
}
The magic of JS closures means that the anonymous function assigned as an event handler inside assignHandler() will be able to access the custom argument of assignHandler() even after assignHandler() has finished.
However, since you seem to be using jQuery's .on() method you don't need to implement anything yourself because jQuery already has functionality for this:
.on( events [, selector ] [, data ], handler(eventObject) )
Note the optional third argument is data. Within the event handler this can be accessed as event.data.
for(a in events){
var handler = function(e){
console.log(e.data);
console.log('<event-name>');
};
var custom = events[a];
$(window).on(events[a], null, custom, handler);
}
I know what you mean...
you want event name when the event is triggered and want to know which event has triggered at run time in function... Am I Right? then you can use Event Object received in handler...
DEMO
var events = ['connect','disconnect','error','connect_failed'];
for(a in events){
var handler = function(e){
console.log(e.type);
console.log('<event-name>');
};
$(window).on(events[a],handler);
}
for(a in events){
$(window).trigger(events[a]);
}
function barvaInfo(event) {
$(document).ready(function(){
var nid = window.event.srcElement.id;
}
this works in IE but not in FF. Can i use jquery for this? i try with JQuery event api but then i do not know how to get ID from it.
If you're using jQuery, you'll need to assign a parameter to your event handlers, then pass the argument to your function on each event.
You may also want to call it from the context of the element that received the event.
// some mouseover event handler
$('div').mouseover( function( e ) {
barvaInfo.call( this, e )
});
function barvaInfo( event ) {
// element that originated the event
var nid = event.target.id;
// in this function, because we're using .call() to invoke it,
// "this" will reference the element that invoked the handler
}
The event object is normalized through jQuery for you and is passed into each event handler:
$('someelement').bind('click', function(event) {
var nid = this.id; // event.target.id
});
within the handler, this refers to the dom node of invocation. So this.id would address the id of the element. Alternative, the event object owns a property called target which also represent the element.
edit
As patrick dw pointed out, this will always be a reference to the node to which the event handler was bound to. event.target is exactly what it says, the element which is the actual target. See comments for an example link.
Where SomeMethod could have:
function SomeMethod(item)
{
item.setAttribute('name', item.id);
}
Instead of:
function SomeMethod(itemId)
{
var someItem;
someItem = document.getElementById(itemId);
someItem .setAttribute('name', someItem .id);
}
Silly example, but the idea is not to send in the id itself, but the actual control calling the method. I swear this can be done but have had no luck searching... partially because I'm not even sure what to search on.
I thought it was self, but self doesn't seem to be what I want when the script I have runs.
Use the this Keyword.
You actually don't need to pass this as an argument to your function, because you've got a click event object that you can access. So:
<script>
function clickEventHandler(event) {
if (!event) {
event = window.event; // Older versions of IE use
// a global reference
// and not an argument.
};
var el = (event.target || event.srcElement); // DOM uses 'target';
// older versions of
// IE use 'srcElement'
el.setAttribute('name', el.id);
}
</script>
I tend to use this approach in all function calls from HTML attributes:-
onclick="SomeMethod.call(this)"
Then in the javascript do:-
function SomeMethod()
{
this.setAttribute('name', this.id);
}
This has a distinct advantage when you may also assign directly to event handler properties in Javascript code:-
document.getElementById("someID").onclick = SomeMethod
If SomeMethod took the context element as a parameter it would very awkward to set up:-
function(id) {
var elem = document.getElementById(id)
elem.onclick = function() { SomeMethod(elem); }
}("someID");
Worse yet this would be memory leaking closure.
At this point: SomeMethod(this) - this returns window object so do not use it. The right way to use this keyword is making it context relevant, so use SomeMethod.call(this).