window.event.srcElement.options(window.event.srcElement.selectedIndex).value works in Internet Explorer (and Chrome) but not in FireFox. How to make this work in FireFox as well?
event.target.options[event.target.selectedIndex].value. Though as always with events you'd have to have passed the event object into a function, so eg.:
<script>
function selectChanged(event) {
var target= event.target || event.srcElement;
doSomethingWith(target.options[target.selectedIndex].value);
};
</script>
<select onchange="selectChanged(event)">...</select>
Setting the handler directly and using this may be easier:
<select id="x">...</select>
<script>
document.getElementById('x').onchange= function() {
doSomethingWith(this.options[this.selectedIndex].value);
};
</script>
Note that looking at options[selectedIndex] is for compatibility with older browsers. These days you can usually just get away with saying select.value.
There is no global event object in Firefox. Events are passed to their handlers as an argument. Also, instead of srcElement, you look for target.
If you use a javascript library like jQuery, all the browser specific quirks are handled for you.
Otherwise, I suggest you to read these articles
http://www.quirksmode.org/js/introevents.html
http://www.quirksmode.org/js/events_properties.html
var addEvent = (function() {
function addEventIE(el, ev, fn) {
return el.attachEvent('on' + ev, function(e) {
return fn.call(el, e);
});
}
function addEventW3C(el, ev, fn) {
return el.addEventListener(ev, fn, false);
}
return window.addEventListener ? addEventW3C:addEventIE;
})();
var domRef = document.getElementById('foo');
addEvent( domRef, 'change', function(e) {
e = e || window.event;
var el = e.target ? e.target : e.srcElement,
value = el.value;
alert( value )
});
in IE, event is a property of window, in modern DOM supporting browsers it's passed as the first argument.
IE uses srcElement where most other browsers (including Firefox) use target.
Also, Firefox passes around event objects, whereas IE just populates the global event object w/the current event's data.
You'll have to handle both in your code. How you handle the 2nd one will depend on how you're assigning the handler.
But here's one way.
function changeHanlder( event )
{
var elem = event.target || event.srcElement;
alert( elem.options[elem.selectedIndex].value );
}
It's also worth noting that all the modern javascirpt libraries handle this abstraction for you.
There are two approaches:
Assume there is markup
<SELECT name="ddlQuery" id="ddlQuery" style="width:273px;"
onchange="GetDropDownValue(event)">
...
on HTML.
One using js function:
function GetDropDownValue(e)
{
var rtnVal = "";
var sel = document.getElementById(getTargetID(e));
for (var i = 0; i < sel.options.length; ++i) {
if (sel.options[i].selected == true) {
rtnVal = sel.options[i].value;
break;
}
}
alert(rtnVal);
return rtnVal;
}
function getTargetID(e) {
if (!e) { var e = window.event; }
var objTarget = e.srcElement ? e.srcElement : e.target;
return objTarget.id;
}
another using jQuery:
$('#ddlQuery').val()
Firefox uses e.htmlEvent.target.nodeName
you can use try/catch to handle both browsers.
Related
I have made a JavaScript tab view of a simple HTML page.
I've added onClick functions for header tags using JavaScript via nodes.
The onClick function performs a function called showTab passing on this as a parameter.
I understand that this is [object window].
The header tag onClick functions are set as shown below:
node.onclick = function() { showTab(this); };
The showTab function is as follows:
function showTab(e)
{
var node = (e && e.target) || (window.event && window.event.srcElement);
alert(node.innerHTML);
}
Everything works fine, when i click on one of the headers, an alert appears with its innerHTML.
However, I did use a little help from Google to achieve this. And I would like some help understanding exactly what this line means:
var node = (e && e.target) || (window.event && window.event.srcElement);
I did my own research and saw it can be considered as the equivalent as sender in C#.
But I would like to know thoroughly how it works and what it is referring to and how it knows which node is calling the showTab function as there are 3 header tags that perform the same function, all without id's.
Ah, the joys of dealing with Events and browser.
The Trident Engine (Internet explorer and others based on that engine) deals with events differently than most (all?) of the other browsers.
<html>
<head>
<title>Test</title>
</head>
<body>
<button id="test_button">Click me</button>
<script>
// UGLY, UGLY, UGLY... don't really use this
var button = document.getElementById("test_button");
if (window.attachEvent) {
button.attachEvent("onclick", showTab);
} else {
button.addEventListener("click", showTab);
}
function showTab(e)
{
// Most browsers pass the event as 'e'
// Microsoft puts the event in window.event
// Either way, event will now point to the object we want.
var event = e || window.event;
// Once again, the different browsers handle the `target` property differently.
// Target should now point to the right event.
var target = event.target || event.srcElement;
alert(target.innerHTML);
}
</script>
</body>
This line:
var node = (e && e.target) || (window.event && window.event.srcElement);
is equivalent to this logic:
var node;
if (e && e.target) {
node = e.target;
} else if (window.event && window.event.srcElement) {
node = window.event.srcElement;
} else {
node = undefined;
}
The purpose of this code is to handle the fact rhat older versions of IE don't pass the event structure to an event handler. Instead, it is stored in a global variable window.event and the event target is also stored in a difference property of the event.
It is a bit more common (and I think more readable) to do something like this:
function showTab(e) {
// get the event data structure into e
e = e || window.event;
// get the source of the event
var node = e.target || e.srcElement;
alert(node.innerHTML);
}
In reality, any decent size project should use a library function for abstracting the differences in event handlers so that this browser-specific code only has to be one place in the project or use a pre-built library like jQuery for this type of thing. Here's a cross-browser event handler:
// refined add event cross browser
function addEvent(elem, event, fn) {
if (typeof elem === "string") {
elem = document.getElementById(elem);
}
function listenHandler(e) {
var ret = fn.apply(this, arguments);
if (ret === false) {
e.stopPropagation();
e.preventDefault();
}
return(ret);
}
function attachHandler() {
// older versions of IE
// set the this pointer same as addEventListener when fn is called
// make sure the event is passed to the fn also so that works the same too
// normalize the target of the event
window.event.target = window.event.srcElement;
var ret = fn.call(elem, window.event);
if (ret === false) {
window.event.returnValue = false;
window.event.cancelBubble = true;
}
return(ret);
}
if (elem.addEventListener) {
elem.addEventListener(event, listenHandler, false);
} else {
elem.attachEvent("on" + event, attachHandler);
}
}
It's getting the dom element which was clicked, either e.target for standards compliant browsers or window.event.srcElement (could be e.srcElement instead for newer IE)
see: http://www.quirksmode.org/js/events_properties.html
I need to use javascript only for this project. Sorry, no jQuery (I feel ashamed as well).
I am adding an addEventListener to a div. "Problem" is that it applies to all its children, too.
Is there a way to avoid this, and have the listener work only for that div?
Thankd in advance.
my code looks like this:
document.getElementById(myObj.id).addEventListener("mousedown", myObjDown, false);
function myObjDown() {
//do stuff here
}
You can tell which element the event actually fired on by reading event.target in your callback.
var el = ...
el.addEventListener('click', function(event){
if (el !== event.target) return;
// Do your stuff.
}, false);
The other option would be to have handlers bound to the child elements to prevent the event from reaching the parent handler, but that is more work and potentially hides events from things that might actually be listening for them above the parent.
Update
Given your example code, you should be able to do this.
var el = document.getElementById(myObj.id);
el.addEventListener("mousedown", myObjDown, false);
function myObjDown(event) {
if (el !== event.target) return;
//do stuff here
}
Also as a general note, keep in mind that none if this will work on IE < 9 because addEventListener is not supported on those.
You can use the currentTarget Event Property
el.addEventListener('click', function(event) {
if (event.currentTarget !== event.target) {
return;
}
// Do your stuff.
}, false);
More details: https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
Here's an alternative, which keeps your myObjDown function in line with a typical event handler. (using e.target as reference to the event invoking element)
var CssSelector = "div.className";
var elms = document.querySelectorAll(CssSelector);
for (i = 0; i < elms.length; i++) {
elms[i].addEventListener("mousedown", myObjDown.bind(null, {"target":elms[i]}, false);
}
function myObjDown(e) {
console.log("event: %o - target: %o", e, e.target);
var elm = e.target;
//do stuff here
}
It was suggested that ..
this method could cause memory leaks with versions of some browsers. If anyone experiences this or has any valuable insights. Please comment.
an alternative, in this regard would be
var CssSelector = "div.className";
var elms = document.querySelectorAll(CssSelector);
for (i = 0; i < elms.length; i++) {
elms[i].addEventListener("mousedown", myObjDown.bind(null, elms[i].id}, false);
}
function myObjDown(id) {
console.log("element: %o ", document.getElementById(id));
//do stuff here
}
this work for me:
document.getElementById(myObj.id).addEventListener("mousedown", myObjDown, false);
function myObjDown(e) {
var myTarget= ele.target;
while (myTarget!== this) {
myTarget= myTarget.parentNode; //finding correct tag
}
//do stuff here
}
Only today I figured out how event propagation works and set out pompously to test it on my existing code base but arghhhhhhh damn you javascript......nothing seems to be simple enough with you :X
Here is my problem, I define a set of events on an anchor:
theLink.setAttribute('onMouseOver','doSomething(this)'); **// works**
theLink.addEventListener("mouseout", function(event){doSomethingElse(event)}, false); **// does not work**
theLink.onmouseout = function(event){doSomethingElse(event)}; **// does not work**
Only if I define events as in the first example then it seems to be working in the second or the third definitions as well. But I can not use that definition because I have to pass event object.
Any hints? I am using firefox.
All three of these worked for me using the following code (in firefox):
HTML:
<a id="link1">Link 1</a>
<a id="link2">Link 2</a>
<a id="link3">Link 3</a>
JS:
var link1 = document.getElementById("link1");
var link2 = document.getElementById("link2");
var link3 = document.getElementById("link3");
window.doSomething = function(event) {
console.log(event);
}
link1.setAttribute('onMouseOver', 'doSomething(this)');
link2.addEventListener("mouseout", function(event) {
doSomething(event)
}, false);
link3.onmouseout = function(event) {
doSomething(event)
};
Here is a jsfiddle with it working: http://jsfiddle.net/magicaj/qk6wU/
You might also consider using a library like jQuery that handles cross browser incompatibility with the addEventListener method that is not supported by some versions of IE, the JS would look something like this:
$("#link1").mouseover(doSomething);
$("#link2").mouseover(doSomething);
$("#link3").mouseover(doSomething);
An answer with cross browserness included
function doSomething( event ) {
if( console && console.log ) {
console.log( this );
console.log( event );
}
else {
alert( this === window ? 'WINDOW' : this.tagName );
alert( event );
}
}
var link1 = document.getElementById("link1");
var link2 = document.getElementById("link2");
var link3 = document.getElementById("link3");
// `this` within your handler will be `window` and not the link
link1.setAttribute( 'onMouseOver', 'doSomething( event )' );
// to attach event listeners you have to do a bit more work
// ( best to make a function rather than doing this each time
if( document.addEventListener ) {
// compliant browsers
link2.addEventListener('mouseover', doSomething, false);
} else {
// internet explorer
link2.attachEvent( 'onmouseover', function() {
// grab the event object from the window
var e = window.event;
// normalise it a bit i.e. make it a bit more like a compliant browsers event object
e.target = e.srcElement;
e.preventDefault = function(){ e.returnValue = false };
e.stopPropagation = function(){ e.cancelBubble = true };
// and forward to your handler making sure that `this` is properly set
doSomething.call( this, e );
});
}
link3.onclick = doSomething;
Note
Avoid wrapping your handlers in unecessary anonymous functions, it's wastefull and you lose the this in the handler
so instead of
link3.onclick = function( event ) { doSomething( event ) };
just assign the handler directly
link3.onclick = doSomething;
I'm having troubles getting the attachEvent to work. In all browsers that support the addEventListener handler the code below works like a charm, but in IE is a complete disaster. They have their own (incomplete) variation of it called attachEvent.
Now here's the deal. How do I get the attachEvent to work in the same way addEventListener does?
Here's the code:
function aFunction(idname)
{
document.writeln('<iframe id="'+idname+'"></iframe>');
var Editor = document.getElementById(idname).contentWindow.document;
/* Some other code */
if (Editor.attachEvent)
{
document.writeln('<textarea id="'+this.idname+'" name="' + this.idname + '" style="display:none">'+this.html+'</textarea>');
Editor.attachEvent("onkeyup", KeyBoardHandler);
}
else
{
document.writeln('<textarea id="hdn'+this.idname+'" name="' + this.idname + '" style="display:block">'+this.html+'</textarea>');
Editor.addEventListener("keyup", KeyBoardHandler, true);
}
}
This calls the function KeyBoardHandler that looks like this:
function KeyBoardHandler(Event, keyEventArgs) {
if (Event.keyCode == 13) {
Event.target.ownerDocument.execCommand("inserthtml",false,'<br />');
Event.returnValue = false;
}
/* more code */
}
I don't want to use any frameworks because A) I'm trying to learn and understand something, and B) any framework is just an overload of code I'm nog going to use.
Any help is highly appreciated!
Here's how to make this work cross-browser, just for reference though.
var myFunction=function(){
//do something here
}
var el=document.getElementById('myId');
if (el.addEventListener) {
el.addEventListener('mouseover',myFunction,false);
el.addEventListener('mouseout',myFunction,false);
} else if(el.attachEvent) {
el.attachEvent('onmouseover',myFunction);
el.attachEvent('onmouseout',myFunction);
} else {
el.onmouseover = myFunction;
el.onmouseout = myFunction;
}
ref: http://jquerydojo.blogspot.com/2012/12/javascript-dom-addeventlistener-and.html
The source of your problems is the KeyBoardHandler function. Specifically, in IE Event objects do not have a target property: the equivalent is srcElement. Also, the returnValue property of Event objects is IE-only. You want the preventDefault() method in other browsers.
function KeyBoardHandler(evt, keyEventArgs) {
if (evt.keyCode == 13) {
var target = evt.target || evt.srcElement;
target.ownerDocument.execCommand("inserthtml",false,'<br />');
if (typeof evt.preventDefault != "undefined") {
evt.preventDefault();
} else {
evt.returnValue = false;
}
}
/* more code */
}
Just use a framework like jQuery or prototype. That's what they are there for, this exact reason: being able to do this sort of thing w/out having to worry about cross-browser compatibility. It's super easy to install...just include a .js script and add a line of code...
(edited just for you Crescent Fresh)
With a framework, the code is as simple as...
<script type='text/javascript' src='jquery.js'></script>
$('element').keyup(function() {
// stuff to happen on event here
});
Here is a function I use for both browsers:
function eventListen(t, fn, o) {
o = o || window;
var e = t+Math.round(Math.random()*99999999);
if ( o.attachEvent ) {
o['e'+e] = fn;
o[e] = function(){
o['e'+e]( window.event );
};
o.attachEvent( 'on'+t, o[e] );
}else{
o.addEventListener( t, fn, false );
}
}
And you can use it like:
eventListen('keyup', function(ev){
if (ev.keyCode === 13){
...
}
...
}, Editor)
Different browsers will process events differently. Some browsers have event bubble up throw the controls where as some go top down. For more information on that take a look at this W3C doc: http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
As for this specific issue setting the "userCapture" parameter to false for the addEventListener will make events behave the same as Internet Explorer: https://developer.mozilla.org/en/DOM/element.addEventListener#Internet_Explorer
You might be better off using a JavaScript framework such as MooTools or jQuery of your choice to ease cross-browser support. For details, see also
http://mootools.net/docs/core/Element/Element.Event
http://api.jquery.com/category/events/
MooTools port of parts of your sample code:
var Editor = $(idname).contentWindow.document;
...
$(document.body).grab(new Element('textarea', {
'id' : this.idname,
'name' : this.idname,
'style': 'display:none;',
'html' : this.html
});
Editor.addEvent('keyup', KeyBoardHandler);
By the way, is it on purpose that you use both idname and this.idname in the code above ?
This works in Firefox, but not IE. Any help would be much appreciated!
var form = document.getElementById('theform')
/* create the event handler */
form.gen.onclick = function( evt ) {
var f = evt.target.form
var y = f.year.value
var m = f.month.value
genCalendar( document, y, m, 'theCalendar' )
}
To get the target of an event in both standards compliant browsers and IE, use
var target = evt ? evt.target : window.event.srcElement;
There's an overview of the different properties of event objects at MDC.
As mentioned, IE does not pass the event object as a parameter. Try this:
var form = document.getElementById('theform')
/* create the event handler */
form.gen.onclick = function( evt ) {
if(!evt)
evt = window.event;
var f = evt.target.form
var y = f.year.value
var m = f.month.value
genCalendar( document, y, m, 'theCalendar' )
}
Or better yet, use a cross-browser library, like Prototype.js or jQuery.
When does this script run? You might have to run this script onload, after the DOM is fully loaded
<script>
function go()
{
alert('dom is loaded: register event handlers now') ;
}
</script>
<body onload=" go(); ">
</body>
This is why you should consider using a javascript library such as jquery, YUI, or prototype. These libraries abstract away the browser based differences which simplifies your coding.
From my own searching the most sucessful was this
function clickHandler(e){
var elem, evt = e ? e:event;
if (evt.srcElement) elem = evt.srcElement;
else if (evt.target) elem = evt.target;
alert (''
+'You clicked the following HTML element: \n <'
+elem.tagName.toUpperCase()
+'>'
)
return true;
}
document.onclick=clickHandler;
Sourced from ther very helpful and explanatory http://www.javascripter.net/faq/eventtargetsrcelement.htm