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);
Related
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.
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
I have a javascript object with a handful of methods, and some of the methods reference each other. The methods become undefined in some situations, regardless of using the key word "this" with them. I'm not sure how to go about it. Here is a snippet of my object below. Method getContent() when accessed in onClickMngLinksBtn method becomes undefined when a button with onClickMngLinksBtn event binding is clicked. This same method works fine when accessed with:
InLineLinksObj.getContent()
I'm hoping the solution is something very basic to Objects in javascript. Any help is much appreciated.
function InLineLinks(formController, fieldController)
{
....
this.getContent = function(){
var field = this.getFieldController().getCustomFieldByName(this.content_field);
if(field){
return field.getValue();
}
return null;
};
this.onClickMngLinksBtn = function(){
var links = [];
var txt = this.getContent();
}
....
}
See here, here or here, or many other places for an explanation of scope and the this keyword in javascript. Essentially,
this always refers to the “owner” of the function we're executing
and when your method is triggered by a DOM event, then the owner is either the window or the HTML element that was clicked (or moused over, etc.), instead of the containing object.
A simple way around it in your case is to define a second variable self which will retain a reference to the containing object.
function InLineLinks(formController, fieldController) {
var self = this;
....
self.getContent = function(){
var field = self.getFieldController().getCustomFieldByName(self.content_field);
if(field){
return field.getValue();
}
return null;
};
self.onClickMngLinksBtn = function(){
var links = [];
var txt = self.getContent();
}
....
}
The way you have it, InLineLinks is a constructor and getContent is a method of it's instances.
Then, you must instantiate InLineLinks to reach getContent:
new InLineLinks().getContent()
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
I created an object and it works great when I have one instance of the object. This isn't the actual Object, but the concept is the same.
function foo(name){
this.name = name;
}
foo.prototype.CreateElement = function(){
var newElement = document.createElement("a");
that = this;
newElement.onclick = function(){
that.SayName(this);
};
document.getElementsByName("body")[0].appendChild(newElement);
}
foo.prototype.SayName = function(LinkObj){
alert(this.name);
LinkObj.href = "http://google.com";
}
I was told that by saving the instance of this to a variable (in this case that), I would still get a reference to the correct object instance for the SayName method. This would leave this to represent the instance of the element passed in from the onclick. This all seems to work properly with only one instance, but when I create multiple instances of the object I end up with the last instance being the instance supplied in the onclick event.
I initialize two objects like this
var ObjOne = new foo("Ted");
ObjOne.CreateElement();
var ObjTwo = new foo("Steve");
ObjTwo.CreateElement();
and when the onclick fires for ObjOne, I get the object instance for ObjTwo and so this.Name is set to Steve.
Does anyone know how I can get the right object instance when the onclick event fires from various instances? I assume i need to bind the correct instance with call, but i'm not really sure how to.
Thanks in advance and hope this wasn't to confusing.
The problem is this line:
that = this;
You declared that without using var, which means it is global, i.e., all your instances are updating the same global that variable. Do this instead:
var that = this;
Then that will be local to each. (That is, local to each closure of the CreateElement function.)
Demo: http://jsfiddle.net/SEsLJ/
Also, document.getElementsByName should be document.getElementsByTagName (assuming you didn't actually give the body a name attribute equal to "body").
I'm building a <ul> dynamically within an object array where each list item calls a function when a link is clicked. However, the function is only ever being passed the parameter from the last item in the object array. Here is my code...
var list = document.createElement("ul");
var object;
for (var i = 0; i < myObjects.length; i++)
{
object = myObjects[i];
listItem = document.createElement("li");
image = document.createElement("img");
image.setAttribute("src", object.image_url)
listItem.appendChild(image);
listItem.appendChild(document.createTextNode(object.title));
link.setAttribute("href", "#");
link.addEventListener("click", function(){someFunction(object.id);}, false);
link.appendChild(document.createTextNode("Click Me!"));
listItem.appendChild(link);
list.appendChild(listItem);
}
element.appendChild(list);
All the variables are declared within this same function, so no globals are used. Before anyone suggests it, I'm not using jQuery because I'm trying to get my head round the basics of javascript before I move on to using any libraries.
Thanks in advance for any help.
Mister B.
Due to the way scope works, the anonymous function has a reference to the variable, not to its value. When you change that variable later, the change is reflected in the anon function.
Perhaps using a closure trick could work?
Change
link.addEventListener("click", function(){someFunction(object.id);}, false);
To
(function(O) {
link.addEventListener("click", function(){someFunction(O.id);}, false);
})(object);
If I'm not mistaken, that oughta create a new variable, whose value will be unaffected by subsequent changes to object in the for loop.
Ah, this is a classic closure issue.
You'll need to pass in the object.id to a wrapper function, like this:
(function(id) {
link.addEventListener("click", function(){someFunction(id);}, false);
})(object.id);