Is there a way to assign unique IDs to createElement objects? - javascript

I have a button when pressed creates new input bars and I would like those input bars to have unique ids, for example - textBar1, textBar2, textBar3 and so on.
I tried creating a variable outside of the function that has the value 0 and then inside the function add the value with +1 for each time the function runs but that doesn't work but instead it assigns the id textBar0 to every element that is created.
Does anyone have any suggestions on how to solve this?
Thanks in advance!
HTML
<label for='ingredient'></label>
<input id="textBar" class="textBar" type="name" name="ingredient">
<div id="textBarPosition"></div>
<div id="addRemoveContainer">
<input id="addBar" type="button" value="Add Ingredient">
JavaScript/jQuery
var counter = 0;
function createSector() {
var input = document.createElement('input');
input.setAttribute("id", 'textBar' + counter +1);
input.type = 'text';
input.name = 'name[]';
return input;
counter = 1;
}
var form = document.getElementById('textBarPosition');
document.getElementById('addBar').addEventListener('click', function(e) {
// step 1: create element and set opacity to 0.
var selector = $(createSector());
selector.fadeIn();
// step 2: append it to its parent.
$(form).append(selector);
$('#removeBar').click(function(){
$("input:last-child").remove(".textBar");
});
});

That is becaus you're not reassinging the changed value to counter.
Use counter+=1 instead or just counter++
input.setAttribute("id", 'textBar' + counter++); // now it should work
What you were doing before was always add 1 to 0

Best way is to use _.uniqueId.
Generate a globally-unique id for client-side models or DOM elements that need one. If prefix is passed, the id will be appended to it.
_.uniqueId('contact_');
=> 'contact_104'

You can use Math.random like this:
input.setAttribute("id", 'textBar_' + Math.random().toString(36));
It is my understanding that when you first call Math.random it generates a sequence of unique random numbers between 0 and 1 using the current time in milliseconds as a seed then returns the first one. Subsequent calls will move through the generated sequence of numbers, returning them one at a time, giving you the ability to generate random unique strings for element IDs.

jQuery Code -
var counter = 0;
function createSector() {
var input = document.createElement('input');
input.setAttribute("id", 'textBar' + counter);
input.type = 'text';
input.name = 'name[]';
return input;
}
var form = document.getElementById('textBarPosition');
document.getElementById('addBar').addEventListener('click', function(e) {
// step 1: create element and set opacity to 0.
var selector = $(createSector());
counter++;
selector.fadeIn();
// step 2: append it to its parent.
$(form).append(selector);
$('#removeBar').click(function(){
$("input:last-child").remove(".textBar");
});
});
Working JSFiddle - http://jsfiddle.net/Ashish_developer/mtafre04/

Related

For every textarea i create, i want it to have its 'personal word count' on it.

The code below is to appear additional 2 textbox and 1 textarea everytime i click a button.
var x=1;
var count=0;
$('body').on('click','#add',function()
{
if(count < 6)
{
$('#div').append("<div class='line'><input type='text' name = 'txta"+x+ "' id='txta"+ x +"'><span class =wordtab></span> <textarea rows='9' onkeyup='countChar2(this)' cols='50' name = 'txtc"+x+ "' id='txtc"+ x +"'></textarea> <span class =wordtab></span><input style = 'width:50px' type='text' name = 'txtb"+x+"' id='txtb"+ x +"'><span class =wordtab></span><button class='delete' value ='Delete Row'>Delete Row</button></div><div style='margin-left: 750px' id='charNum" + x + "'></div>");
count++;
x++;
}
else
alert("Maximum 6 Skills");
});
$('body').on('click','.delete',function()
{
$(this).closest('.line').remove();
count--;
});
The below function is the code that i currently have (which i know its wrong) to put in a counter for every textarea that i added in.
function countChar2(val)
{
var len = val.value.length;
if (len >= 200)
{
val.value = val.value.substring(0, 500);
}
else
{
var id = "charNum" + x;
$(id).text((200 - len)+" words left");
}
};
So my goal is that everytime i click on the add row and start typing on the textarea, it will show the word count for that particular texarea just right below the textarea box.
To get a unique counter added to each textarea, you could append another div to the textarea with a specific class e.g.
Set the HTML structure to something such as:
<textarea></textarea><div class='text-count-area'>Word Count: 0</div>
Add the following JS at the point where each textarea is added e.g. just before 'count++' in your original code (note: this is not the most efficient way of doing this, but this will work easily with your current code):
// Bind the text area to the keyup event
$("textarea").on('keyup', function(val) {
// Simple word count
var words = this.value.match(/\S+/g).length;
// Write the word count to the immediate text-count-area div afterwards
$(this).next(".text-count-area").text("Text count" + words);
});
The word count is kept simple here for readability, but the logic from other answers (highlighted in the comments) could be implemented at this stage.
A JS Fiddle demo of this working is here.
Let see your example:
You add each div by .append method, it's correct
You count input symbols by onkeyup event, it's correct too
All you need is update your countChar2 function because this function has wrong body in that lines:
var id = "charNum" + x;
$(id).text((200 - len)+" words left");
First of all: try to debug your code via developer tools in your favorite browser with breaks in that lines. This step can give your much more and quickly info than posting question in stackoverflow :)
For onkeyup event you should use link to this object instead of id inside your function:
$(val).parent().find('.words-left').val((200 - len));
This line uses val as a link to textarea object in just appended line. .parent() gives you access to wrapper and find() finds input for words left field. (I've added '.words-left' class to your input, see my fiddler bellow). And this code works in stage of your just added line.
Your code of $('body').click() should be executed, when document is fully loaded and DOM ready. But all your ids that you will create in future doesn't appends that DOM. That's why your delete function works properly - that function uses class selector instead of id.
Proposed by me code doesn't uses id selector because it is not needed. All that needs to me - link to current object in new line, val - what I need for that operation.
BTW: When you implement function that works with objects, such as onkeyup='countChar2(this)', better way to use object as passed variable - var countChar = function(obj) {. Because val is using for scalar values in common way.
You can check my code here https://jsfiddle.net/jo0cd3yr/1/

Changing a dynamically created label's text with keyup() issue

I am creating a form dynamically and therefore edit the form elements’ properties. When attempting to change the label, assigning an auto-generated id works fine but when changing this label using the generated id, the function or keyup() from jQuery keeps calling all the previously created label id(s). this means when i want to edit one label, it ends up editing every label.
HTML
<input type="text" id="change-label"><br><br>
<button id="add-button">add label</button>
<div id="add-label"></div>
JavaScript/jQuery
$('#add-button').click(function(){
var div = document.createElement('div');
var textLabel = document.createElement('label');
var labelNode = document.createTextNode('untitled');
textLabel.appendChild(labelNode);
textLabel.id = autoIdClosure();
$('#change-label').val('untitled');
div.appendChild(textLabel);
$('#add-label').append(div);
});
var autoIdClosure = (function(){
var counter = 0;
var labelId = "textInputLabel";
return function(){
counter += 1;
var id = labelId + counter;
editLabelWrapper(id)
return id;
}
})();
function editLabelWrapper(id){
function editLabel(){
var value = $(this).val();
$("#"+id).text(value);
}
$("#change-label").keyup(editLabel).keyup();
}
I’ve already found an alternative using onkeyup="$('#'+globaID).text($(this).val());", but I need to understand what I was doing wrong so I can learn from it.
JSFiddle
I think you are overthinking the matter...
Instead of using an unique id, rather use classes, makes it easier to handle.
So change <div id="add-label"></div> to <div class="add-label"></div>
Then what you want to do is, when a value is given in #change-label you want it in the last div.add-label.
So the function will become this:
$("#change-label").on('keyup', function() {
$('.add-label:last').text( $(this).val() );
});
Next what you want to do is bind a function to #add-button. Once it gets clicked, we want to add a new div.add-label after the last one. And empty the #change-label. You can do that by using this function:
$('#add-button').on('click', function() {
$('.add-label:last').after('<div class="add-label"></div>');
$('#change-label').val('');
});
Updated Fiddle

How do I attach eventListeners to dynamically generated radio buttons?

I want to attach an event listener to each radio input click, so that I can retrieve that radio input's value and assign it as the value of a new property in the current question object in the allQuestions array.
I'm not sure why I'm having difficulty making choice.addEventListener work.
My HTML:
<div id="quiz"></div>
<button id="button">Next</button>
My JavaScript:
var allQuestions = [{question: "What is the capital of the Czech Republic?",
choices: ["Skopje", "Budapest", "Prague", "Bucharest"],
correctAnswer: 2},
{question: "When was the Declaration of Independence signed?",
choices: ["1492", "1776", "1812", "1791"],
correctAnswer: 1}];
var quiz = document.getElementById("quiz");
var index = -1;
var next = function() {
index += 1;
quiz.innerHTML = "";
for (var i = 0; i < allQuestions[index]['choices'].length; i++) {
var choice = document.createElement('input');
choice.type = 'radio';
choice.name = 'choices';
choice.value = i;
choice.addEventListener('click', function() {
alert('hi');
});
quiz.appendChild(choice);
quiz.innerHTML += allQuestions[index]['choices'][i] + '<br>';
}
};
var button = document.getElementById('button');
button.addEventListener('click', next);
You're trying to use markup and DOM elements at the same time. Here's the main problem:
quiz.appendChild(choice);
quiz.innerHTML += allQuestions[index]['choices'][i] + '<br>';
The first line appends a DOM element with an attached event handler to the quiz element. The second line converts the contents of quiz to an HTML string, appends some further text (markup) to that string, and then parses that HTML and replaces the content of quiz with the parsed result. That wipes out anything not represented in the HTML, including the dynamically-added event handler.
The solution is not to do innerHTML += ..., which is almost always a bad idea. In this particular case, you can do this:
quiz.appendChild(choice);
quiz.appendChild(document.createTextNode(allQuestions[index]['choices'][i]));
quiz.appendChild(document.createElement('br'));
...which also has the advantage that any characters that are special in HTML (like <) are treated literally (because that's what createTextNode does).
Now, having said that, you don't need handlers on every radio button. Instead, you can use event delegation by using a handler on your quiz element, and then using e.target within the handler to know which radio button was clicked:
quiz.addEventListener("click", function(e) {
if (e.target.tagName.toUpperCase() === "INPUT") {
var value = e.target.value; // The value of the clicked radio button
}
});
That way, you don't have to worry about adding handlers dynamically; just do it once, after the quiz element is known to exist, and you can update its content all you want without having to worry about attaching handlers to the radio buttons within.
To do event delegation in general, you usually have to loop starting from e.target and going to its parentNode in order to find the element you're interested in (say you're interested in a div, but the click was on a span inside it); but of course, input elements can't have any elements inside them, so it's simple here.
You're probably wondering why the check on the tag name. If you associate your radio buttons with label elements (as is usually good practice), either by putting the input inside the label or using the for attribute on the label, you'll see two clicks when you click the label: One on the label itself, and a second one on the input that the label relates to. We're only interested in the one on the actual radio button.
Here's a simple example of the delegation above:
var quiz = document.getElementById("quiz");
quiz.addEventListener("click", function(e) {
if (e.target.tagName.toUpperCase() === "INPUT") {
var value = e.target.value; // The value of the clicked radio button
console.log("The value of that radio button is " + value);
}
});
for (var n = 0; n < 5; ++n) {
var div = document.createElement("div");
div.innerHTML = '<label><input type="radio" value="' + n + '" name="answer"> Radio ' + n + '</label>';
quiz.appendChild(div);
}
<div id="quiz"></div>

jQuery: changed input value is not used for new addition

I have a hidden input field, wich has the value 0:
<input type="hidden" class="test" value="0" />
Now I added a button with some JS to add 0.5 to the value each time the button is clicked:
<a class="addition-input">Click me</a>
Here is the JS part:
$('a.addition-input').click(function(event) {
event.preventDefault();
var currentValue = parseInt($('input.test').val());
var step = 0.5;
var newValue = currentValue + step;
$('input.test').val(newValue);
});
So, the first time i click the link/button, the value gets from "0" to "0.5".
But then, when I click the link/button the second time, it won't change, it just stays "0.5".
I think that jQuery doesn't get the new input value by the second time click, it probably thinks the value is "0".
How can I fix that?
Update:
Here's the fiddle: https://jsfiddle.net/m7pvjrve/1/
Use
var currentValue = parseFloat($('input.test').val());
instead of
var currentValue = parseInt($('input.test').val());
parseInt() converts 0.5 to 0 everytime and the value you get is 0.5 which is actually the step value
Demo: http://jsfiddle.net/GCu2D/657/

Using On Blur to Call a Function

I am trying to have a web page update a value when the text field loses focus. I have tried a number of different suggested variations for the onblur event but nothing seems to work as expected. Currently I have the onblur in the html code on line 59
<input name="qty1" id="qty1" size="8" value="0" onBlur="productCost()" />
and I have tried to make the correction in the script as well.
function productCosts()
{
var totalMap = document.getElementById("qty1").onblur();
totalMap.value = ("qty1") * ("price1");
//$("#cost1").html (totalMap.toFixed(2));
alert(totalMap)
//var totalPlanner = ('qty2') * ('price2');
//var totalHiker = ('qty3') * ('price3');
}
I have created a fiddle to show the entire program. http://jsfiddle.net/Jn6LQ/ Any help would be really greatly appreciated.
It's easy with jQuery
$('#qty1').bind('blur', productCosts)
or with JS
document.getElementById('qty1').addEventListener('blur', productCosts)
Note: In the below, $ is not jQuery, the OP is using it as a shortcut for getElementById.
The line
totalMap.value = ("qty1") * ("price1");
multiplies the string "qty1" with the string "price1". Perhaps you meant to look up the elements, and then get their values:
totalMap.value = $("qty1").value * $("price1").value;
Separately, using onXyz attributes is usually not best practice. Instead:
$("qty1").onblur = productCosts;
$("price1").onblur = productCosts;
function productCosts() {
var value = $("qty1").value * $("price1").value;
$("cost1").innerHTML = value.toFixed(2);
}
(There I'm assuming the price can be changed as well, but that may not be the case on your page.)
Looking at the fiddle, though, you have a much bigger problem: You want to do that for multiple lines. Using id values to do that is going to make for gainly, over-large code. Instead, use a class on each input, and then relate it to the other inputs in the row using the fact they're all in the same row.
function productCosts() {
var row = this.parentNode.parentNode,
qty = row.querySelector(".qty"),
price = row.querySelector(".price"),
cost = row.querySelector(".cost"),
value = qty.value * price.value;
cost.innerHTML = value.toFixed(2);
}
var list, i;
list = document.querySelectorAll(".qty, .price");
for (i = 0; i < list.length; ++i) {
list[i].onblur = productCosts;
}
jQuery.blur() looks like what you're looking for:
$('#qty1').blur(function(){
alert('here');
});

Categories

Resources