Dynamically created form fields keep having the same ID - javascript

I dynamically add some text fields to my page with this line of code:
var textboxCount = 0;
$('#addFields').on('click', function(){
var TextField = document.createElement("input");
TextField.setAttribute("type", "text");
TextField.setAttribute("value", textboxCount);
TextField.setAttribute("name", "textbox");
TextField.setAttribute("class", "foo");
TextField.setAttribute("id", "textbox" + textboxCount);
TextField.setAttribute('onkeyup','doSomething('+textboxCount+');'); // for FF
TextField.onkeyup = function() {doSomething(textboxCount);}; // for IE
jQuery('#TextfieldList').append(eleText);
textboxCount += 1; //Increment the count
});
Now I need the unique ID of the field in this function:
function doSomething(id){
alert(id);
}
But when I call the function, I keep getting the same ID with every added field. The value in the textfield is correct though.

Extremely common problem. Change the keyup handler:
TextField.onkeyup = function(textboxCount) {
return function() {
doSomething(textboxCount);}; // for IE
};
}(textboxCount);
(Get rid of the "For FF" line; it's not necessary at all.)
If you don't introduce a new lexical scope somehow, then all of your event handlers will be referring to the exact same "textboxCount" variable. By doing something like what I've shown above (and there are variations), you ensure that each event handler has its own private copy of the counter as it stood at the time the handler was created.

Since you want to get the id of an element in its own event handler you can bypass the whole closure issue by just referencing this.id, where this is the element and id is its id property
TextField.onkeyup = function() {doSomething(this.id);};

You could just use the jQuery library you have in play:
$('#addFields').on('click', function () {
var thisId = $('.foo').length + 1;
var TextField = '<input type="text" name="textbox" class="foo" value="' + thisId + '" id="textbox' + thisId + '">';
jQuery(TextField).appendTo('#TextfieldList');
});
$('#TextfieldList').on('keyup', '.foo', function () {
doSomething($(this).attr('id'));
// or
doSomething(this.id);
});
function doSomething(id){
alert(id);
}
Sample jsFiddle: http://jsfiddle.net/mHT7Z/

Related

Input jQuery get old value before onchange and get value after on change

I have an input text in jQuery I want to know if it possible to get the value of that input text(type=number and type=text) before the onchange happens and also get the value of the same input input text after the onchange happens. This is using jQuery.
What I tried:
I tried saving the value on variable then call that value inside onchange but I am getting a blank value.
The simplest way is to save the original value using data() when the element gets focus. Here is a really basic example:
JSFiddle: http://jsfiddle.net/TrueBlueAussie/e4ovx435/
$('input').on('focusin', function(){
console.log("Saving value " + $(this).val());
$(this).data('val', $(this).val());
});
$('input').on('change', function(){
var prev = $(this).data('val');
var current = $(this).val();
console.log("Prev value " + prev);
console.log("New value " + current);
});
Better to use Delegated Event Handlers
Note: it is generally more efficient to use a delegated event handler when there can be multiple matching elements. This way only a single handler is added (smaller overhead and faster initialisation) and any speed difference at event time is negligible.
Here is the same example using delegated events connected to document:
$(document).on('focusin', 'input', function(){
console.log("Saving value " + $(this).val());
$(this).data('val', $(this).val());
}).on('change','input', function(){
var prev = $(this).data('val');
var current = $(this).val();
console.log("Prev value " + prev);
console.log("New value " + current);
});
JsFiddle: http://jsfiddle.net/TrueBlueAussie/e4ovx435/65/
Delegated events work by listening for an event (focusin, change etc) on an ancestor element (document* in this case), then applying the jQuery filter (input) to only the elements in the bubble chain then applying the function to only those matching elements that caused the event.
*Note: A a general rule, use document as the default for delegated events and not body. body has a bug, to do with styling, that can cause it to not get bubbled mouse events. Also document always exists so you can attach to it outside of a DOM ready handler :)
Definitely you will need to store old value manually, depending on what moment you are interested (before focusing, from last change).
Initial value can be taken from defaultValue property:
function onChange() {
var oldValue = this.defaultValue;
var newValue = this.value;
}
Value before focusing can be taken as shown in Gone Coding's answer. But you have to keep in mind that value can be changed without focusing.
Just put the initial value into a data attribute when you create the textbox, eg
HTML
<input id="my-textbox" type="text" data-initial-value="6" value="6" />
JQuery
$("#my-textbox").change(function () {
var oldValue = $(this).attr("data-initial-value");
var newValue = $(this).val();
});
I have found a solution that works even with "Select2" plugin:
function functionName() {
$('html').on('change', 'select.some-class', function() {
var newValue = $(this).val();
var oldValue = $(this).attr('data-val');
if ( $.isNumeric(oldValue) ) { // or another condition
// do something
}
$(this).attr('data-val', newValue);
});
$('select.some-class').trigger('change');
}
I found this question today, but I'm not sure why was this made so complicated rather than implementing it simply like:
var input = $('#target');
var inputVal = input.val();
input.on('change', function() {
console.log('Current Value: ', $(this).val());
console.log('Old Value: ', inputVal);
inputVal = $(this).val();
});
If you want to target multiple inputs then, use each function:
$('input').each(function() {
var inputVal = $(this).val();
$(this).on('change', function() {
console.log('Current Value: ',$(this).val());
console.log('Old Value: ', inputVal);
inputVal = $(this).val();
});
my solution is here
function getVal() {
var $numInput = $('input');
var $inputArr = [];
for(let i=0; i < $numInput.length ; i++ )
$inputArr[$numInput[i].name] = $numInput[i].value;
return $inputArr;
}
var $inNum = getVal();
$('input').on('change', function() {
// inNum is last Val
$inNum = getVal();
// in here we update value of input
let $val = this.value;
});
The upvoted solution works for some situations but is not the ideal solution. The solution Bhojendra Rauniyar provided will only work in certain scenarios. The var inputVal will always remain the same, so changing the input multiple times would break the function.
The function may also break when using focus, because of the ▲▼ (up/down) spinner on html number input. That is why J.T. Taylor has the best solution. By adding a data attribute you can avoid these problems:
<input id="my-textbox" type="text" data-initial-value="6" value="6" />
If you only need a current value and above options don't work, you can use it this way.
$('#input').on('change', () => {
const current = document.getElementById('input').value;
}
My business aim was removing classes form previous input and add it to a new one.
In this case there was simple solution: remove classes from all inputs before add
<div>
<input type="radio" checked><b class="darkred">Value1</b>
<input type="radio"><b>Value2</b>
<input type="radio"><b>Value3</b>
</div>
and
$('input[type="radio"]').on('change', function () {
var current = $(this);
current.closest('div').find('input').each(function () {
(this).next().removeClass('darkred')
});
current.next().addClass('darkred');
});
JsFiddle: http://jsfiddle.net/gkislin13/tybp8skL
if you are looking for select droplist, and jquery code would like this:
var preValue ="";
//get value when click select list
$("#selectList").click(
function(){
preValue =$("#selectList").val();
}
);
$("#selectList").change(
function(){
var curentValue = $("#selectList").val();
var preValue = preValue;
console.log("current:"+curentValue );
console.log("old:"+preValue );
}
);

$(document).on('focus' or $(document).bind('input', not trigger on dynamically added row?

I used $(document).on('focus' or $(document).bind('input','input:text' so my method for automatically change duplicate input values from table1 to table2 via(keypress), but my code does not trigger,If the user will change the input (from new row) that was added to table dynamically.
This happen,for instance, click the Add row button,Edit the new "Apple" field and see that this will not change the duplicate "Apple" on table2.
See this for FIDDLE for demo.
$("input:text").each(function () {
var elem = $(this),
oldValue;
$('input:text').trigger('focus');
$(document).on('focus', 'input:text', function () {
elem.data('oldVal', elem.val());
elem.data('oldLen', elem.data('oldVal').length);
});
$(document).bind('input', 'input:text', function (event) {
oldValue = elem.data('oldVal');
elem.data('oldVal', elem.val());
if (elem.val().length - elem.data('oldLen') > 1) {
alert('Most certainly pasted');
}
elem.data('oldLen', elem.data('oldVal').length);
foo(oldValue,elem.val());
});
});
$("input").blur();
.bind() doesn't take a selector argument, only .on() does. If you're binding to dynamically-added elements, you need to use .on().
$(document).on('input', 'input:text', function ...);
Corrected fiddle
The other problem is that you're using $("input:text").each(). That will only process the elements that existed when the page was loaded. You don't need that loop, just bind your event handlers normally. You don't need the variables elem and oldValue outside handlers; within the handler, $(this) is the element that the event was triggered on, and you can get oldValue from .data().
$(document).on('focus', 'input:text', function () {
var elem = $(this);
elem.data('oldVal', elem.val());
elem.data('oldLen', elem.data('oldVal').length);
});
$(document).on('input', 'input:text', function (event) {
var elem = $(this);
var oldValue = elem.data('oldVal') || '';
elem.data('oldVal', elem.val());
if (elem.val().length - oldValue.length > 1) {
alert('Most certainly pasted');
}
elem.data('oldLen', elem.data('oldVal').length);
foo(oldValue, elem.val());
});
I have refactored your code. **Note : ** You should not have a static id when adding elements dynamically. Ids are supposed to be unique and as it is, your inputs will all have the same id input_0.
Instead, since you have only one input per row, get the index of the row to create ids dynamically (input0, input1,..., inputN). See the code below, it's commented.
Another thing, your table2 was not updated because you are adding rows dynamically and the $(selector).each() is only running once. if you put it inside a function to be invoked every time a row is added everything will work fine.
//----------adding a row
$(document).on("click", '.tdAdd', function () {
var table = $(this).parents("#table1");
// get the row
var currentRow = $(this).closest("tr");
// get the current value of the input
// in order to duplicate it
var currentVal = currentRow.children().find("input[type='text']").val();
// one way to create a cell
var buttonCell = '<td><input type="button" value="Add Row" class="tdAdd"/></td>';
// but I'd rather do it like this
// because I can assign any value as an attribute - dynamic
var inputCell = $("<td>").append($('<input type="text"/>').attr({
id : "input" + (currentRow.index() + 1),
value : currentVal,
class : "ttt"
}));
table.append(
$("<tr>").append(buttonCell, inputCell)
);
// invoking this function in order to update $(selector).each()
updateEachFn();
});
and the wrapper function
// wrap $(selector).each() inside a function to be invoked
// every time a row is added to keep everything up to date
function updateEachFn() {
$("input:text").each(function () {
var elem = $(this),
oldValue;
$('input:text').trigger('focus');
// do not use document, because it will unnecessarily go through
// every single input -- bad for performance
// also you are already on an input:text ie each() above
elem.bind('focus', function () {
elem.data('oldVal', elem.val());
elem.data('oldLen', elem.data('oldVal').length);
});
elem.bind('input', function (event) {
oldValue = elem.data('oldVal');
elem.data('oldVal', elem.val());
if (elem.val().length - elem.data('oldLen') > 1) {
alert('Most certainly pasted');
}
elem.data('oldLen', elem.data('oldVal').length);
foo(oldValue,elem.val());
});
});
}
$("input").blur();
// invoke it once for input0
updateEachFn();
here's a jsfiddle for you to play with

How to avoid multiple function call

I have click event function to create a new dom elements. Basically, every time I click a button. It allows create a new hyperlink tag.
I also want to have a functionality that if new created hyperlink clicked, I want to call different function.
Please have a look following code,
var id = 1;
$('#create').on('click', function() {
id ++
$('.players').append('<a href="#" class="new" data-id='+ id + '> ' + id + 'player</a>');
getId()
});
function getId() {
$('.new').on('click', function() {
var id = $(this).data('id')
alert(id);
});
}
My problem is I don't want to run getId() function everytime I clicked a button, But if I run getId() function alone, new created hyperlink won't effent that functionality.
Is anyway I can call getId() function once. and It still going to effect a new created hyperlink?
You can use one method to use the function only for once.
function getId() {
$('.new').one('click', function() {
var id = $(this).data('id')
alert(id);
});
Use delegation, then there is no need to attach the event handler function every time you append. Remove your getId() function and replace it with a delegated on() method:
var id = 1;
$('#create').on('click', function () {
id++;
$('.players').append('<a href="#" class="new" data-id=' + id + '> ' + id + 'player</a>');
});
$('.players').on('click', '.new', function(e) {
e.preventDefault();
var id = $(this).data('id')
alert(id);
});
JSFiddle
Try to use on() for dynamic elements like,
$(function(){
var id = 1;
$('#create').on('click', function() {
id ++;
$('.players').append('<a href="#" class="new" data-id='+id+'>'+id+'player</a>');
});
$(document).on('click','.new', function() {
//use ^ document or your parent element players
var id = $(this).data('id');
alert(id);
});
});

Assign click-event on a new element in the event itself

I want to create a new element and assign this element the same event for onclick, which it has created it.
DEMO
$(function(){
var counter = 0;
$('.sub').click(function(event){
event.stopPropagation();
counter++;
$div = $(this); // makes more sense in the original code
$div.append('<div class="sub" title="subsub">subsub' + counter + '</div>');
//$div.find('.sub').click // <-- ?????
});
});
In my demo I want to create a new subsub for every sub, which was clicked. Than I want to add the same click event to the new subsub element.
Could anyone help me with this?
I've found nothing for this problem. Maybe I don't have the correct keywords for google or SO :/
Just use event Delegation
$(document).on('click', '.sub', function(event){
Your click events seem to be working correctly at this point,because you are using append which actually nests the new div inside the div that is clicked. Try using after and the functionality breaks.
$(function(){
var counter = 0;
$(document).on('click', '.sub', function(event){
event.stopPropagation();
counter++;
$div = $(this); // makes more sense in the original code
$div.after('<div class="sub" title="subsub">subsub' + counter + '</div>');
});
});
Check Fiddle
Why not create proper elements instead :
$(function(){
var counter = 0;
$('.sub').on('click', doStuff);
function doStuff(event) {
event.stopPropagation();
counter++;
var $div = $(this),
$sub = $('<div />', {'class':'sub',
title : 'subsub',
text : 'subsub' + counter,
on : {
click : doStuff
}
}
);
$div.append($sub);
}
});

Javascript classes & event handlers

I have a problem with this javascript code:
function MyClass() {
var id_nr = Math.ceil(Math.random() * 999999);
this.button_id = 'button_' + id_nr;
}
MyClass.prototype = {
createButton: function() {
var msg = 'Button \'' + this.button_id + '\' was clicked';
var my_button = (
'<input type="button" id="'
+ this.button_id
+ '" value="Click Me" /\>'
);
document.body.innerHTML += '<div>' + my_button + '</div>';
document.getElementById(this.button_id).onclick = function() { alert(msg); }
}
};
window.onload = function() {
var s = new MyClass();
s.createButton();
};
Yes, this current code works fine. But the problem appears when I add more than one MyClass objects:
window.onload = function() {
var s = new MyClass();
s.createButton();
var w = new MyClass();
w.createButton();
/* ...and many other buttons */
};
For some reason the onclick event will be triggered only if I click the button that was created last. And I don't know why.
One workaround could be something like this:
<input type="button" onclick="javascript:doSomeThing();" />
But unfortunately this is not the proper solution right row, because my goal is that the onclik event should be able to call another class methods as well. (Those methods are not created yet).
How can I make this code work properly? Any kind of a help is appreciated.
When you use innerHTML the contents get stripped from the DOM and then readded and parsed again, breaking any past event listener that you might have added.
If you want to do it in vanilla JS, consider using appendChild() and, also, I would suggest addEventListener(). Your code would then look like so:
var my_button = document.createElement('input');
my_button.type = 'button';
my_button.id = this.button_id;
my_button.value = 'Click me';
document.body.appendChild(my_button);
my_button.addEventListener('click', function () { alert (msg) });
Working example with vanilla Javascript
If you are up to using some jQuery, this would be so much easier to implement. Your method would look something like:
var my_button = $('<input>')
.prop('type', 'button')
.prop('id', this.button_id)
.val('Click Me')
.on('click', function () { alert(msg) } );
$('body').append(my_button)
Working example with jQuery
Or you could perhaps use the jQuery.on() method to delegate an event handler to all subsequent instances of your buttons.
Working example with delegated event handler
The use of innerHTML here seems to break the event listener "onclick".
You can avoid this by using the document.createElement method to create your html element :
var but = document.createElement("input");
but.type = "button";
but.id = this.button_id;
but.value = "Click me";
document.body.appendChild(but);
Personaly, I prefer use jQuery for manipulating the DOM tree element, as it offer really powerfull tools for this.

Categories