Creating a button dynamically with arguments for onclick [duplicate] - javascript

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How to pass arguments to an event handler function and still use ‘this’ reference?
I've done a bit of searching but I'm struggling to find a solution to this.
Anyway:
function CreateMe(){
//....
var mycell = row.insertCell(-1);
var myelement3 = document.createmyelement("input");
myelement3.type = "button";
myelement3.value = "Delete";
myelement3.onclick = DeleteMe;
myelement3.name = "Delete[]";
mycell.appendChild(myelement3);
//....
}
function DeleteMe(){
alert(this);
}
I have a form with a button that calls CreateMe which dynamically creates a button. What I'm after is to be able to pass in arguments to the DeleteMe function when this dynamic button is clicked; in particular this:
onclick="DeleteMe(this.parentNode.parentNode.rowIndex)"
from: http://www.java2s.com/Code/JavaScript/HTML/Deletingtablerows.htm
I'm at a bit of a loss on how to proceed here, so if anybody could lend a hand it would be appreciated.
Edit: Just to be clear, what is being asked is how I can pass arguments from the onclick event of the dynamically generated button to the DeleteMe function. Clearly I am unable to do this as this would simply evaluate the function immediately:
myelement3.value = "Delete";
myelement3.onclick=DeleteMe(this.parentNode.parentNode.rowIndex);
myelement3.name = "Delete[]";

You are nearly there. .onclick is expected to be a function, so all you have to do is wrap that function call into another function:
myelement3.onclick = function() {
DeleteMe(this.parentNode.parentNode.rowIndex);
// or
// DeleteMe.call(this, this.parentNode.parentNode.rowIndex);
// to set `this` inside `DeleteMe` to the DOM element as well.
};
If the browser supports .bind, you could even do:
myelement3.onclick = DeleteMe.bind(
myelement3,
myelement3.parentNode.parentNode.rowIndex
);
but that would evaluate myelement3.parentNode.parentNode.rowIndex at the moment of creation and not when the element is clicked. If elements change their position, this could lead to problems, and in this case you'd rather go with the first solution.
Alternative, since this refers to the clicked element, you can access the row index inside DeleteMe:
function DeleteMe(){
var index = this.parentNode.parentNode.rowIndex;
}
// ...
myelement3.onclick = DeleteMe;
This works as long as you call DeleteMe only as event handler and not manually.

You can try this
function DeleteMe(e){
e = e || window.event;
var el = e.target || e.srcElement;
// here el is your button that's been clicked
alert(el.parentNode.parentNode.rowIndex);
}​

Related

An event seems to start automatically even if it is not called [duplicate]

This question already has answers here:
JavaScript setTimeout() won't wait to Execute? [duplicate]
(3 answers)
Closed 3 years ago.
An event seems to start automatically even if it is not called. It should only start if something is typed.
The code automatically takes each cell and applies an event to the click that causes a box to appear and according to the cell changes the information contained in them where there is an input which in turn has an event when something is typed but starts automatically .
After a cell is clicked (elementToChange is the inner text of the clicked cell):
js
function changeMemberSurname(elementToChange) {
var showOptions = document.getElementById("showChangeOptions");
showOptions.className = "show";
var input = document.createElement("input");
input.value = "Surname";
input.type = "text";
input.id = "ChangeMemberInput";
input.name = "Surname";
input.addEventListener("keyup", changeMemberOldNew(elementToChange));
showOptions.appendChild(input); //append it to the empty div
};
function changeMemberOldNew(elementToChange) {
var inputValue = document.getElementById("ChangeMemberInput").value;
var showValue = document.getElementById("showChangeText");
showValue.innerText = "before: " + elementToChange + " - after: " + inputValue + ".";
};
changeMemberOldNew is the function that starts automatically but should not.
Why it autostart?
Thanks in advance.
When you add your event listener, you're actually invoking the function and passing its return (which is undefined) to addEventListener(). You need to pass the function itself to addEventListener(), which is done with the function name but without parenthesis (it's the parenthesis that invokes the function). However, since you need to pass an argument to the function it's not that straight forward but you can solve this by wrapping it in a handler function, like this:
var keyupHandler = function() {
changeMemberOldNew(elementToChange);
};
input.addEventListener("keyup", keyupHandler);
Now it's the keyupHandler() function that gets passed to addEventListener() and that function is what invokes the changeMemberOldNew() function with the argument at the proper time.
The problem is that you are calling the function, then passing the result of the function call to the event listener, rather than passing the function itself. You need to get rid of the argument in the parentheses:
input.addEventListener("keyup", changeMemberOldNew);

setAttribute() doesn't "remember" the value assigned to it's ID in a function if its a defined variable?

This function creates a unique label and corresponding delete button on the screen that, when pressed, deletes itself and the label by its unique ID. In order to be able to distinguish itself from other label-delete pairs it is assigned a unique ID based on the selection that caused its existence (from a select menu).
function saveSelection(selection) {
var element = document.getElementById("div1");
var del = document.createElement("button");
del.type = "button";
del.id = selection;
del.setAttribute("onclick", "deleteSelection(selection)");
del.appendChild(document.createTextNode("delete"));
element.appendChild(del);
}
function deleteSelection(selection) {
var element = document.getElementById("div1");
element.removeChild(document.getElementById(selection));
console.log("deleted");
}
The problem is, when I assign the selection to the buttons ID I have to refer to it by its variable name (actually called 'selection' in the function). When the delete button is pressed I suspect the code looks at the value passed in the onclick function and just sees 'selection' because it has "forgotten" what "selection" was, thus causing an error. Either this or I am not using proper syntax (lack/presence of ' or " quotes) and am thus passing/assigning it incorrectly.
Google Chrome's error console points out this line as the problem:
del.setAttribute("onclick", "deleteSelection(selection)");
specifially citing the 'selection' variable as being not defined in
deleteSelection(selection)
selection is not a global variable - presumably, it's scoped to the function that creates the element. Inline handlers that reference variables can only reference global variables.
But inline handlers are terrible practice anyway, they're basically eval inside HTML markup - better to attach the handler properly with Javascript instead, and no need for any ids:
document.querySelector('#add').onclick = function saveSelection() {
var element = document.getElementById("div1");
var del = document.createElement("button");
del.type = "button";
del.onclick = del.remove;
del.textContent = 'delete';
element.appendChild(del);
};
<div id="add">add</div>
<div id="div1"></div>

jQuery: use var shortcut to assign data and how to chain function to run on load and click

I've got a two-part question.
One: can I use the last variable I set to update the value on the line after if (!last) {? i.e., something like last = size;?
var j$ = jQuery.noConflict();
function updateCount() {
var self = j$(this),
last = self.data('last'),
size = self.val().length,
span = j$('.currentCount');
if (!last) {
self.data('last', size);
} else if (last != size) {
span.text(size);
self.data('last', size);
}
}
j$('textarea[id$=textBody]').on('propertychange change click keyup input paste', updateCount);
Secondly, can I chain my .on('propertychange ... line to have updateCount run as soon as the script is loaded?
Question 1:
No, you can not use simply the assignment to the variable because there is no data-binding in jQuery. So updating last variable will never update the data-last of the jQuery object.
Question 2:
This is what I am used to do:
j$('textarea[id$=textBody]').on('propertychange change ...', updateCount).change();
Where change() automatically triggers the function.
For Q1: No you can't. If you want data binding to work, you can try AngularJS where 2 way data binding between UI and model is possible.
Q2: My solution would be something like this using immediate function
$('textarea[id$=textBody]').on('propertychange change click keyup input paste', (function(){
updateCount();
return updateCount;
}()));
The last variable has a copy of the value in self.data('last'), it is not a pointer, so you would have to do something like this:
last = size;
self.data('last', last);
For the second question, you can trigger the event or just call the function:
j$('textarea[id$=textBody]').trigger('propertychange');
// or
j$('textarea[id$=textBody]').each(updateCount);

Why does the context of "this" change in this example?

I'm embarrassed to admit how many hours I spent trying to figure this problem out. It turned out that the order of the two lines under the "problem area" comment change the context of "this" when it's used in the prototype addSong function.
var PlaylistView = function(config){
this.config = config || {};
this.$addSongForm = this.config.addSongForm || $('#addSongForm');
this.$song = this.config.song || $('#song');
// problem area
this.addSong = $.proxy(this.addSong, this);
this.listenAddSong();
};
PlaylistView.prototype.listenAddSong = function(){
this.$addSongForm.on('submit', this.addSong);
};
PlaylistView.prototype.addSong = function(event){
//Here is where I'm getting different context for this
var songName = this.$song.val();
//do some stuff...
return false;
};
return PlaylistView;
When the two lines are in the order shown I get the behavior I want: "this.$song" contains a jquery selector that I had set when initializing the PlaylistView object. However, when I had the order reversed, looking at the inspector in Firefox showed that "this" referred to the actual form in the DOM.
Why is that?
The reason is because this.addSong !== $.proxy(this.addSong, this). When you run $.proxy and then listenAddSong the bound function is used and this is your Playlist object. When you reverse the order then the unbound function is passed to the listener in listenAddSong. You replace the unbound function with the bound function in this line:
this.addSong = $.proxy(this.addSong, this);
So, depending on which function this.addSong points to when listenAddSong runs, you either get the correct behavior, or the incorrect behavior.

Checking form values with re-usable function

I need some help writing a re-usable function for form checking. I want to call the function on an element of my form and perform a value validation; however I am not sure I have written the function correctly to accept the targeted element.
Here is a fiddle where you can find all the code.
My questions:
By using the element object as a parameter of the function, does this get the specified element when the user types in values in that input element?
And can I write the function in this way and then pass it into addEventListener?
I am trying to adapt the simple function found at this link.
The piece of JS code I am trying to get to work is as follows:
var A = {
invoiced: document.getElementById("invoiced"),
checkValue: function (event, elem) {
if(elem.validity.typeMismatch)
elem.setCustomValidity("Only number(s) and '+' and '-' signs");
else
elem.setCustomValidity("");
}
};
A.invoiced.addEventListener("keyup", A.checkValue, false);
checkValue: function(event) {
var elem = event.target || event.srcElement;
...

Categories