I have a function that creates a new <a> element and I want to add a onclick event to it, which is a function that increases the given value by 1.
In the function, I create these elements:
A number within spantags:
var spantags = document.createElement("span");
var anzahl = 1;
spantags.innerHTML = anzahl;
And the mentioned <a> element:
var plus = document.createElement("a");
plus.innerHTML = "+";
plus.onclick = more(spantags.innerHTML);
This, however, executed the function already in the function that creates this, so the number was increased to 2 on creation.
I read this answer on a similar question:
https://stackoverflow.com/a/249084/1972372
This example worked, the alert only came up when the + was clicked on, but it is an inner function there, not a declared one like my "more(element)".
So my question is: Is it possible to set the onclick attribute to a declared function on a newly created element, like in my example, but prevent it from running immediately?
(The other article had a jQuery answer too, but unfortunately I have no knowledge about jQuery and cannot use it)
Yes, just wrap it in a "proxy" function:
plus.onclick = function() {
more(spantags.innerHTML);
};
Sure, but first you have to understand that plus.onclick = more(spantags.innerHTML); will call more with the argument spantags.innerHTML and assign the result that is returned from that function call to plus.onclick.
You could wrap it in a proxy function as suggested previously, or you could take advantage of the bind method to bind the arguments to the function itself:
plus.onclick = more.bind(null, spantags.innerHTML);
Read up on Bind here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Related
Pretty basic question, but I'm not able to find a suitable answer anywhere as I'm not sure what verbiage to use. I'm trying to better understand what is happening here so I can keep myself from making this mistake again. As you can see on the last line, I'm trying to set the onclick event, but it immediately invokes the function. The solution is to remove the parenthesis, but what exactly is that doing? What is the difference between the two? Thanks for any help.
let element = document.querySelector("button");
function turnButtonRed (){
element.style.backgroundColor = "red";
element.style.color = "white";
element.innerHTML = "Red Button";
}
element.onclick = turnButtonRed();
think of turnButtonRed as a variable.
var turnButtonRed = function(){ return 2 };
Now, if you use that variable to pass it to onclick, for example, you have 2 possibilities
element.onclick = turnButtonRed; // this is setting onclick to a function
element.onclick = turnButtonRed(); // this is setting onclick to whatever the function returns (2 in this case).
You want onclick to be set to a function, not the result of a function. turnButtonRed() gives you the result of the function, turnButtonRed is the function itself.
In the statement element.onclick = turnButtonRed(); you are assigning the result of calling turnButtonRed, not that function itself. Simply remove the ().
Here is why. I refer you to the mighty Table of Operator Precedence!
Your line of code has two operators, assignment and function call. Let's see:
Function call is 20
Assignment is 3
We do things in operator precedence order, from highest to lowest. So what is happening is, you are evaluating the function call turnButtonRed() first, then assigning that result to the handler. Which isn't what you want.
Just remove the function call, and assign the function:
element.onclick = turnButtonRed;
Here, we are not calling the function. Instead we assign the function itself as an event handler.
Now, the preferred, modern way of doing this is to add an event handler:
element.addEventListener("click", turnButtonRed);
I leave it as an exercise to the reader to explore why this might be preferred.
This question already has answers here:
What exactly is the parameter e (event) and why pass it to JavaScript functions?
(5 answers)
Closed 4 years ago.
There is an example in "Head first JavaScript" book. This piece of code is unblurring an image on click. The code works, but I don't understand how, though it's an extremely simple piece of code.
The function init is called when a window is loaded. getElementsByTagName gives an HTMLCollection. A click on an image invokes a showAnswer function.
Now there is a mystery for me.
window.onload = init;
function init() {
var images = document.getElementsByTagName("img");
for (var i = 0; i < images.length; i++) {
images[i].onclick = showAnswer;
}
};
function showAnswer(e) {
var image = e.target;
var name = image.id;
name = name + ".jpg";
image.src = name;
}
There should be a parameter e. How this parameter is being created, from where? When showAnswer is called in init, there are no parameters given to it.
Considering the fact that I'm using a .target method on it, it should be an object. How does the browser know that this object has name e?
Why images[i].onclick = showAnswer; and not showAnswer();?
images[i].onclick = showAnswer is defining the event handler function to be run when images[i] is clicked. If you were to use showAnswer() there, it would run immediately in the init function which is probably not what you want.
images[i].addEventListener('click', showAnswer) is another way to write that, which might be more intuitive.
Event handler functions pass in an event object, which is what the 'e' is referring to. 'e.target' is referring to the element itself.
A reference for DOM events:
https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events
(breaking myself of the habit of answering questions in comments...)
There should be a parameter e. How this parameter is being created, from where?
When you do images[i].onclick = showAnswer, that assigns "showAnswer" as the event handler for the "click" event for the DOM element named in images[i].
Later, when the user clicks that element (or the event gets triggered by some other method), the browser constructs the Event object, which contains a whole lot of information about that specific event. It then calls your event handler, passing along the Event object as the first (and only) parameter.
When showAnswer is called in init, there are no parameters given to it.
In your init function, you don't call showAnswer; you assign it as the event handler for clicks on images. The event is what passes the parameter to the handler, not your init.
Considering the fact that I'm using a .target method on it, it should be an object. How does the browser know that this object has name e?
That's the name you gave the parameter in the function. You could use any name, but e or evt are a common convention for event objects.
Why images[i].onclick = showAnswer; and not showAnswer();?
If it were showAnswer() you'd be assigning the return value of the function to the click handler. (Which in this case would be undefined, because showAnswer doesn't return anything.) With showAnswer you assign the function itself to the handler.
window.onload = unblurMonaLisa;
function unblurMonaLisa() {
var images = document.getElementsByTagName("img");
for (var i = 0; i < images.length; i++) {
images[i].onclick = showAnswer;
}
};
function showAnswer(eventObj) {
var image = eventObj.target;
var name = image.id;
name = name + ".jpg";
image.src = name;
};
The above code switches a blurred image for an image that is not blurred when said image is clicked. The code works just fine. My questions are about the eventObj that is passed to the showAnswer function. When is the eventObj created in this code? Is the scope of eventObj local? If I assigned the onclick event to two different variables would that create two eventObj and if so how would I access them individually?
When is the "eventObj" created in this code?
When the the event you are interested in happens, in this case a click, your callback function is automatically executed by the environment. When the callback function is executed, it is given an event object as an argument, which you can choose to ignore it in your function signature. (i.e. your showAnswer function could be like this function showAnswer() {...}). The event object is a regular object that holds information about the event that just happened.
Is the scope of "eventObj" local?
Yes, it is.
If I assigned the onclick event to two different variables
You cannot add two different callback functions by using .onclick. You should use addEventListener() if you want to add multiple callback functions to the same event.
would that create two "eventObj" and if so how would I access them individually?
The event object that would be created for that event would be just one, and it would be passed to all callback functions.
For more info on events read this: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
Also check out the answer to this question, which is similar
UPDATE:
To answer to your comment:
the browser creates a unique Event Object every time an event occurs whether we have a handler listening for that event or not?
Correct.
We can pass this unique object to our handler
Correct again.
I noticed on your other post they used "e" in place of "eventObj"
You can name it whatever you want in your function. As long as you put something as your function parameter (function(e) {} for example) your function will accept the event object.
People usually name that parameter e, short for event, or event, to indicate what kind of thing is this parameter, but you can name it however you want, like any other parameter of any other function.
This is a follow up question from my last question.
Simple javascript prototype issue
I am a bit new using JavaScript prototype so sorry for the second post.
I want to assign the clicked element id to the this.name array.
task.prototype.init=function(){
this.name=[]; //this.name array has to be defined here
for (var i; i<5; i++){
var Link=document.createElement('a');
Link.innerHTML='click';
Link.id=value[i]; //I want to assign the value to the this.name array
Link.href='#'
Link.onclick=this.changeName;
document.body.appendChild(Link);
}
}
task.prototype.changeName=function(){
//How do I push the this.id to the property this.name?
//the code below won't work because this refer to the <a> element.
this.name.push(this.id);
return false;
}
Any tips for the task?
Your prototype is okay, the problem is that this on event handlers is always the element that caused the event to be triggered. In JavaScript, the value of this inside a function depends on how the function is called.
If you want this to be bound to a certain value, you can create a bound function with Function.prototype.bind:
var newChangeName = this.changeName.bind(this);
Link.onclick = newChangeName;
Note however that bind is IE9+ only. A workaround would be:
var that = this;
Link.onclick = function() {
that.changeName();
};
(Style note: I'd use link instead of Link; the convention in js is to leave uppercase initials to constructors).
Use bind to set the desired this for the changeName callback:
Link.onclick=this.changeName.bind(this);
Ok, I have one JavaScript that creates rows in a table like this:
function AddRow(text,rowID) {
var tbl = document.getElementById('tblNotePanel');
var row = tbl.insertRow(tbl.rows.length);
var cell = row.insertCell();
var textNode = document.createTextNode(text);
cell.id = rowID;
cell.style.backgroundColor = "gold";
cell.onclick = clickTest;
cell.appendChild(textNode);
}
In the above function, I set the cell's onclick function to call another JavaScript function called clickTest. My question is when I assign the onclick event to call clickTest, how do I set parameter information to be sent when the clickTest method is called on the cell's onclick event? Or, how do I access the cell's ID in the clickTest function?
Thanks,
Jeff
Try this:
cell.onclick = function() { clickTest(rowID); };
The idea is that you are binding the onclick handler to the anonymous function. The anonymous function calls clickTest with rowID as the parameter.
In the clickTest function you should have access to a the this variable. Try this inside of clickTest function:
alert(this.id);
This will refer to the DOM element that fired the event.
Basically, there isn't really a way to pass parameters to an event handler function. The reason for that is that the browser is executing the function based on an event and you are not actually calling the function.
You can use closures which allow you to access local variables (to the closure) when you assign the event handler function. That would look like this:
cell.onclick = function() { alert(this.id); alert(cell.id); };
Were cell.id is the locally scoped variable that is still considered in scope when the event handler is executed.
The suggested solutions work most of the time except for special scenarios.
In case you have a for loop adding onclicks calling another function with different parameters and when testing you realize all your item's behave like the last item, you may consider adding onclick as a text:
for(var loopObj of loopObjList)
mydiv.setAttribute('onclick', 'javascript: pick_option(' + loopObj.id + ', "' + loopObj.value + '");' );