Using the following code works in all browsers, but in Firefox it gives the error "TypeError: answer is undefined quiz.js:13"
function getAnswer() {
var answer = window.event,
btn = answer.target || answer.srcElement;
return btn.id;
}
In my full code line 13 is
btn = answer.target || answer.srcElement;
I'm using this piece of code to check which button is pressed.
Is there any way to fix this?
window.event only works in IE. For other browsers, the event is passed as the argument to the handler.
Since this is not your handler of the event, you will have to do this in the actual handler and pass that information to your getAnswer function instead of using the global window.event
function getAnswer(e) {
var btn = e.target || e.srcElement;
return btn.id;
}
document.addEventListener('click', function(e) {
e = e || window.event;
console.log(getAnswer(e));
});
Or if using the HTML attribute, you have to pass it from the HTML.
<p onclick="alert(getAnswer(event))"></p>
Yes...
Firefox does not have a window.event but rather uses an event object passed in. (To the best of my knowledge, this code should not work under Chrome either.)
function getAnswer(event) {
var answer = event || window.event,
// Added the `var` here.
var btn = answer.target || answer.srcElement;
return btn.id;
}
Related
I have the following:
Element.prototype.makeDraggable = (elem = null) => {
//this.draggable = true;
this.setAttribute("draggable", "true");
this.ondragstart = (e) => { e.dataTransfer.setData("text", elem ? elem.id : e.target.id); }
};
When the browser gets to that function it throws an error on the first line:
Drag.js:7 Uncaught TypeError: n.setAttribute is not a function
Where n is the minified name of the element, or so I thought.
as you can see in the picture, this seems to be an Element, but n is.. well I don't know what it is. Am I doing it wrong?
At this same point, if I do this.draggable = true in the console it works just fine... You can also see that I tried doing it in the code but that doesn't work either.
Any ideas?
The this you see in the debugger is the actual this value; the this you see in the source view is the source-mapped version of n, and the value of n isn’t what you want it to be.
You used an arrow function, so you got lexical this. That’s what arrow functions do. To access the this from call time (what’s generally intended when adding methods to a prototype), use a non-arrow function:
Element.prototype.makeDraggable = function (elem = null) {
//this.draggable = true;
this.setAttribute("draggable", "true");
this.ondragstart = (e) => { e.dataTransfer.setData("text", elem ? elem.id : e.target.id); }
};
See also Are 'Arrow Functions' and 'Functions' equivalent / exchangeable?.
Finally, extending the prototypes you have some of the least control over – browser built-ins – is considered a bad idea. (You could produce a conflict with future extensions to the spec, for example – or with other libraries you use.) A standalone function usually works better:
const makeDraggable = (target, elem = null) {
target.draggable = true;
target.ondragstart = (e) => { e.dataTransfer.setData("text", elem ? elem.id : e.target.id); }
};
I need to found other way how to use javascript function.
var b = ce("input"); // Here I create element.
b.setAttribute("name", "g4");
b.value = "Centimetrais(pvz:187.5)";
b.onfocus = function() { remv(this); };
b.onchange = function() { abs(this); };
b.onkeypress = function() { on(event); }; // I need to change this place becose then I pass "event" argument function doesn't work.
ac(1, "", b); // Here I appendChild element in form.
Here is the function:
function on(evt) {
var theEvent = evt|| window.event;
var key = theEvent.keyCode || theEvent.which;
key = String.fromCharCode( key );
var regex = /^[0-9.,]+$/;
if( !regex.test(key) ) {
theEvent.returnValue = false;
if(theEvent.preventDefault) theEvent.preventDefault();
}
}
In IE and chrome it work but in mozilla doesn't. Any alternative how to fix it for firefox?
Also at this path other function working in mozilla if pass other argument like "car","dog",this. For example:
firstFunction();
function firstFunction() {
var b = ce("input"); // Here I create element.
b.onkeypress = function() { on("hi!"); };
ac(1, "", b); // Here I appendChild element in form.
}
function on(evt) {
alert(evt);
}
If I understand your question correctly, the problem is that you're not accepting the event argument in the main handler. E.g., in your first example:
b.onkeypress = function() { on(event); };
it should be
b.onkeypress = function(e) { on(e || window.event); };
// Changes here --------^ and --^^^^^^^^^^^^
You're doing that in on, but in on, it's already too late, you've lost the argument provided to the onXYZ function.
The reason your code works in Chrome and IE is that IE uses a global event object instead of (or in modern versions, in addition to) the one it actually passes into the handler, and Chrome replicates that behavior for maximum compatibility with websites that expect that. Firefox does not.
What does this JavaScript snippet mean? The (evt) part is so confusing; evt is not a boolean. How it works?
function checkIt(evt) {
evt = (evt) ? evt : window.event
var charCode = (evt.which) ? evt.which : evt.keyCode
}
evt = (evt) ? evt : window.event is just the inline if syntax. It's equivalent to this code:
if (evt) {
evt = evt;
} else {
evt = window.event;
}
If evt is truthy, evt will be left alone. If evt isn't truthy, it will be replaced with window.event.
It's for event listeners.
IE6-IE8 used a totally different event method than the W3C standard.
When an event fires, a W3C-standard browser will pass an event object in the callback:
function keyPressed (e) { /* do stuff with e */ }
In your case, it's keydown (or something else using keyCode).
IE didn't support this, instead it had window.event which was updated every time an event happened.
So your function is checking to see if an object was passed into it:
evt = (evt) ? evt : window.event;
// does `evt` exist, and is it anything but '', 0, false, null, undefined, NaN
// yes: evt = itself (W3C)
// no: evt = window.event (IE6-8)
Then the code asks if evt.which exists, to try to figure out where to get the keyCode from.
evt.keyCode is what you should be using for modern browsers, in the case of keydown and keyup.
Assignment expressions like that are evaluated from right to left, so this means:
if evt has a truthy value, assign this value back to evt
if not, assign the value of window.event regardless of its content to evt
It means: if the evt parameter has a value then keep the value, if it doesn't have a value then use window.event instead.
The ? and ':' symbols are part of the ternary if operator:
var w = x ? y : z;
so above you assign either y or z to w depending on whether x is considered to be a true or false value.
If the checkIt function was called without passing in an evt argument i.e. checkIt() then inside the function the evt variable will have the value of undefined which is treated as false within an if condition.
I am trying to do something simple: I have a bunch of Images which are being load through JS.
I attach an event listener to the load event, and after the Image is being loaded, in the listener function I would like to get the calling Image and retrieve properties from it.
Here is my code, simplified:
function loadImages() {
for (var i = 0; i < arrDownloadQueueBasic.length; i++) {
var path = arrDownloadQueueBasic[i].path;
var img = new Image();
img.type = arrDownloadQueueBasic[i].type;
img.attachEvent(img, 'load', setBasicElement);
img.src = path;
}
}
function setBasicElement(e) {
var caller = e.target || e.srcElement;
alert(caller); // THIS DOESNT WORK - RETURN NULL
alert(caller.type) // OF COURSE THIS DOESNT WORK AS WELL...
}
There are a couple of things that you need to correct. First, the attachEvent method should not be used for browsers other than IE. You should structure your code to check if the method is implemented and then act accordingly like so:
if(img.addEventListener) {
img.addEventListener('load', setBasicElement, false);
}
else if(img.attachEvent) {
img.attachEvent('onload', setBasicElement);
}
else {
img.onload = setBasicElement;
}
The other issue is that you need to prefix the event name with "on" when using attachEvent.
EDIT
You can get the caller by using the following code in the setBasicElement function:
var caller = e.target || e.srcElement || window.event.target || window.event.srcElement;
Here is a working example - http://jsfiddle.net/BMsXR/3/
Try this:
var caller = window.event ? window.event.srcElement : e.target;
If I remember rightly IE doesn't pass the event object as a parameter when you've used attachEvent(), but it has a global event object.
I use event delegation in such way:
elWraper.onclick = (function(){
//how to get here "event" object
e = e || window.event;
var t = e.target || e.srcElement;
//event handler
return function(){
//manipulations with "t" variable
}
})();
how to get "event" object within the immediately executed function?
elWraper.onclick = (function(){
// misc stuff here
//event handler
return function(e){
e = e || window.event;
var t = e.target || e.srcElement;
//manipulations with "t" variable
}
})();
In standards compliant browsers the event object is the first parameter passed into the callback function. In IE it is a global variable (which is what e = e || window.event is trying to determine). Therefore, the function that you return by the immediately executed function should accept the event object declared as its first (and usually only) argument.
Clarification
Since people are wondering (and probably they are wondering why the OP accepted this answer) there are uses for this that is not clear from the OP's question. One is to create a closure to a variable to track something:
/* Count number of clicks,
* WITHOUT USING GLOBAL VARS!
*/
el.onclick = (function(){
var counter = 0;
return function(e){
e = e || window.event;
var t = e.target || e.srcElement;
counter ++;
alert('detected '+counter+' clicks!');
// do stuff with t or e ...
}
})();
also, this is the classic way of assigning event handlers in loops:
/* Use double closure to break closure in loop!
*/
for (var i=0; i<stuff.length; i++) {
var el = stuff[i];
el.onclick = (function(x){
return function(e){
e = e || window.event;
var t = e.target || e.srcElement;
alert(x);
// do stuff with t or e ...
}
})(i);
}
Or maybe the OP just thought that he could 'cache' the event object and mistakenly believed he could use this to do it. In which case, reading my explanation (instead of just the code) should enlighten the reader as to why that would be a bad idea.
elWraper.onclick = function (e) {
//how to get here "event" object
e = e || window.event;
var t = e.target || e.srcElement;
//manipulations with "t" variable
};
I think slebetman's answer is correct according to your question. However, I don't see the point of what you are doing. If you are trying to abstract the browser's event differences, you can use something like this.
function createHandler( context, handler ) {
return function (e) {
e = e || window.event;
var t = e.target || e.srcElement;
handler.call (context || window, e, t);
}
}
Then you can use it like
div.onclick = createHandler(div, function(e, t){
alert ("actual clicked target is " + t.id);
alert ("handler was set on node " + this.id);
});
Note that you can pass anything as the context (the 'this' keyword in the handler)
It's good to know this stuff, but jquery or many other libs already do this for you and it's a lot more tested than your code will ever be and it takes care of many more browser differences than this small function. But if this all you need, this does keep code bloat down.