I want to dynamically add the id and for attribute for each input and label element.
<div id="splash">
<div class="tab">
<input id="tab-1">
<label for="tab-1"><label>
</div>
<div class="tab">
<input id="tab-2">
<label for="tab-2"><label>
</div>
<div class="tab">
<input id="tab-3">
<label for="tab-3"><label>
</div>
</div>
So basically I would want the id for the input to be tab-# with the # increasing by 1 for each input field and the same for the "for=" attribute for the label.
It's super easy. Just iterate through each .tab, using each's index argument, and modify the attributes of the elements.
$('.tab').each(function (index) {
var tabName = 'tab-' + (index + 1);
$('input', this).attr('id', tabName);
$('label', this).attr('for', tabName);
});
Jsbin: http://jsbin.com/rawatag/4/edit?html,js,output
Ok.
I won't give you a straight answer but this should be more useful in future.
Basically make the container <div id=splash>
Then run this command document.getElementById("parentID").innerHTML += "Something here"
This will add the content (pay attention to. The += sign) to the div (splash)
Then, just wrap this in a loop using a counter to get the desired result
Eg: ...innerHTML += "<div id=tab-" + counter + "></div>"
Note that this can be done in raw JS. No JQuery required.
No need for jQuery here:
es5 (jsfiddle)
function assignInputsAndLabels(root) {
var children = root.children;
var tabNumber = 1;
for (var i = 0; i < children.length; i++) {
if (children[i].classList.contains('tab')) {
children[i].getElementsByTagName('input')[0].setAttribute('id', 'tab-' + tabNumber);
children[i].getElementsByTagName('label')[0].setAttribute('for', 'tab-' + tabNumber);
tabNumber++;
}
}
}
assignInputsAndLabels(document.getElementById('splash'));
es6
function assignInputsAndLabels(root) {
const children = root.children;
let tabNumber = 1;
for (let i = 0; i < children.length; i++) {
if (children[i].classList.contains('tab')) {
children[i].getElementsByTagName('input')[0].setAttribute('id', `tab-${tabNumber}`);
children[i].getElementsByTagName('label')[0].setAttribute('for', `tab-${tabNumber}`);
tabNumber++;
}
}
}
assignInputsAndLabels(document.getElementById('splash'));
The parameter to the function is the wrapper of the elements that have the class of tab. In your case, you'd pass in the DOM node of the element with id of splash. So you'd call the function like this:
assignInputsAndLabels(document.getElementById('splash'));
I have done it using javascript.Check it below
function init(){
var sel = document.getElementsByClassName("tab");
var i=1;
for(let obj of sel){
var attr = "tab-"+i;
obj.getElementsByTagName('input')[0].setAttribute("id",attr);
obj.getElementsByTagName('label')[0].setAttribute("for",attr);
i++;
}
}
addEventListener("load",init);
<div class="tab">
<input type="text">
<label></label>
</div>
<div class="tab">
<input type="text">
<label></label>
</div>
Related
I have a list of table columns. I would like to display them in one row.
What am I trying is :
for (var i = 0; i < key.length; i++) {
writeToScreen3('<div class="col-sm">' + key[i] + '</div>'); //column name
}
function writeToScreen3(message) {
var pre = document.createElement("p"); //I realize I am creating another element <p> How to do it diffrently?
pre.innerHTML = message;
output.appendChild(pre);
}
What I need is this transferred to JavaScript :
<div class="container">
<div class="row">
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
</div>
</div>
What I also tried :
function test8() {
$("#output").html('<div class="container">< div class= "row" >'); //but it always closes these 2 divs here . I want it not to close it. output is a div field
}
You can do something like this:
function createContainer(columns) {
function createDivWithClass(cls) {
const div = document.createElement('div');
div.classList.add(cls);
return div;
}
const container = createDivWithClass('container');
const row = createDivWithClass('row');
container.appendChild(row);
for (let i = 0; i < columns.length; i++) {
const column = createDivWithClass('col-sm');
column.textContent = columns[i];
row.appendChild(column);
}
return container;
}
const container = createContainer([1, 2, 3, 4]);
document.getElementById('output').appendChild(container);
console.log(container.outerHTML);
<div id="output"></div>
Here, I've defined a function called createDivWithClass to make it easier to create a <div> and set a class name to it.
Then, I'm using this function to create a <div class="container">, create a <div class="row"> and add that to the container, and then go through the columns array and create <div class="col-sm"> and add those to the row element.
Just like you can append elements to the #output element in the DOM, you can also append elements to elements that you've created and are not yet in the DOM.
i have a html tag like this :
<div data-ctrl="master">
<div data-text="txtName"></div>
</div>
<div data-ctrl="master">
<div ><span data-text="txtName"></span> Wiratama</div>
</div>
and in js code i have :
var txtName = 'Yoza';
i want to insert html to every element in document with attribute data-text="txtName" in element with data-ctrl="master" with pure js.
function updateData(txtName){
var html = '<b>' + txtName + '</b>';
//update data for every element with attribute data-text txtName here
var allElements = document.getElementsByTagName('*');
for (var i = 0, n = allElements.length; i < n; i++) {
if (allElements[i].getAttribute("data-text") !== null) {
if (allElements[i].getAttribute("data-text") === 'txtName') {
console.log(nodeTemplate);
// allElements[i].innerHTML = html;
}
}
}
}
that is my js code i tried to.
Use querySelectorAll to return a list of nodes which match your selection. Then iterate over each of them, setting the innerHTML as you go:
function updateData(txtName){
var nodes = document.querySelectorAll('[data-ctrl="master"] [data-text="txtName"]');
for (i = 0; i < nodes.length; ++i) {
nodes[i].innerHTML = "<b>" + txtName + "</b>";
}
};
updateData("Yoza");
<div data-ctrl="master">
<div data-text="txtName"></div>
</div>
<div data-ctrl="master">
<div ><span data-text="txtName"></span> Wiratama</div>
</div>
On all modern browsers, and also IE8, you have querySelector and querySelectorAll on elements (and also on document), which accept CSS selectors. querySelector returns the first matching element (or null); querySelectorAll returns a list.
So if you have an element and want to find all of the elements within it that have the attribute data-text="txtName", you can do:
var list = theElementYouHave.querySelectorAll('[data-text="txtName"]');
So for example:
// Get some element
var element = document.getElementById("foo");
// Find all elements inside it that have `data-text` (at all)
snippet.log("Descendant elements with a data-text attribute: " +
element.querySelectorAll("[data-text]").length);
// Find the *first* element with `data-text="txtName"` and change its
// text to "Yoza":
var txtNameElement = element.querySelector('[data-text="txtName"]');
if (txtNameElement) {
txtNameElement.innerHTML = "Yoza";
}
<div id="foo">
<div data-ctrl="master">
<div data-text="txtName"></div>
</div>
<div data-ctrl="master">
<div><span data-text="txtName"></span> Wiratama</div>
</div>
</div>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
I need some help with the click event, I'm trying to have an individual counter that is incremented by the click event that I have on the img. I've tried many variations, I want to resolve this without using jQuery.
<script async>
var count = 0;
var clickerCount = document.getElementsByClassName('clicker');
var cat = {
count : 0,
counter: function(){
this.count++;
clickerCount.textContent = "Kitten Click Count :" + this.count;
console.log("counter function working");
console.log(cat.count);
}
};
function modifyNum(){
cat.counter();
console.log("modifyNum function working");
}
</script>
</head>
<body>
<div style="display:inline">
<div>
<img src="http://placekitten.com/200/296" id="cat0" onclick="modifyNum();">
<p id='clicker'>Kitten Click Count :</p>
</div>
<div>
<img src="http://placekitten.com/200/296" id='cat1' onclick="modifyNum();">
<p id='clicker'>Kitten Click Count :</p>
</div>
</div>
For a start, you are using id='clicker' in two places (IDs are supposed to be unique), and then using document.getElementsByClassName, which returns nothing because you used an ID and not a class.
Once you do change it to a class, document.getElementsByClassName will return an array of elements. You'll have to use clickerCount[0] and so on, or loop through the array.
This example should work. I've separated the HTML from the Javascript because it looks clearer for me. You can use it as an example to expand / create your own in your own way.
Hope it help
HTML:
<div style="display:inline">
<div>
<img src="http://placekitten.com/200/296" id="1" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-1">0</span>
</div>
<div>
<img src="http://placekitten.com/200/296" id="2" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-2">0</span>
</div>
</div>
JS:
var imagesCountable = document.getElementsByClassName("countable");
var counters = [];
for (var i = 0; i < imagesCountable.length; i++) {
counters[imagesCountable[i].id] = 0;
imagesCountable[i].onclick = function(e) {
document.getElementById("counter-for-" + e.currentTarget.id)
.innerHTML = ++counters[e.currentTarget.id];
}
}
var imagesCountable = document.getElementsByClassName("countable");
var counters = [];
for (var i = 0; i < imagesCountable.length; i++) {
counters[imagesCountable[i].id] = 0;
imagesCountable[i].onclick = function(e) {
var cElem = document.getElementById("counter-for-" + e.currentTarget.id);
cElem.innerHTML = ++counters[e.currentTarget.id];
}
}
<div style="display:inline">
<div>
<img src="http://placekitten.com/200/296" id="1" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-1">0</span>
</div>
<div>
<img src="http://placekitten.com/200/296" id="2" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-2">0</span>
</div>
</div>
I have solved this problem in this JSFiddle!
If you can hardcode the IDs then it's easier in my point o view to just manipulate things by ID.
<div>
<img src="http://placekitten.com/200/296" id="cat0" onclick="counter(0);">
<p id='clicker0'>Kitten Click Count :</p>
<input type="hidden" id="counter0" value="0">
</div>
function counter(id) {
var cnt = parseInt(document.getElementById("counter" + id).value);
cnt++;
document.getElementById("counter" + id).value = cnt;
document.getElementById('clicker' + id).innerHTML = 'Kitten Click Count :' + cnt;
}
It's not the same approach but I find it easy to understand.
Hope it helps.
Ok, so first off you have two elements with the id of 'clicker'. You probably meant for those to be classes and ids. So when you call modifynum() it cant locate those because the class doesn't exists. Second, your JS is loading before your HTML elements. So when the JS gets to this line:
var clickerCount = document.getElementsByClassName('clicker');
It is going to find nothing, even if you correct the class names. So you want to move your JS to the footer of your HTML document, or wrap the code in a method that is called on pageLoad().
I think that should take care of it. Your object, for the most part, looks correct.
I have here the following script which is causing me some errors:
var sections = ["#general_info", "#address_records", "#employment_history", "#driver_experience", "#military_experience", "#eeo_survey", "#psp_notice", "#eva"];
for(var i = 0; i < sections.length; i++){
$(sections[i]).find('input, select').each(function(){
$(this).change(function(){
validate();
$(this).closest('.placement').find('.module-heading').removeClass('module-heading-bad');
$(this).closest('.placement').find('.glyphicon').addClass('glyphicon-ok text-success');
$(this).closest('.placement').find('.glyphicon').removeClass('glyphicon-warning-sign text-danger');
$(sections[i]).find('input, select').each(function(){
if($(this).closest('div').hasClass('has-error')){
$(this).closest('.placement').find('.module-heading').addClass('module-heading-bad');
$(this).closest('.placement').find('.glyphicon').addClass('glyphicon-warning-sign text-danger');
$(this).closest('.placement').find('.glyphicon').removeClass('glyphicon-ok text-success');
return false;
}
});
});
});
}
function validate(){
var driving_qs = ['driving_exp_qa', 'driving_exp_qb', 'driving_exp_qc', 'driving_exp_qd'];
for( var i = 0; i < driving_qs.length; i++){
if($('input[name='+driving_qs[i]+']:checked').val()){
$('input[name='+driving_qs[i]+']').closest('.form-group').removeClass('has-error');
$('input[name='+driving_qs[i]+']').closest('.form-group').addClass('has-success');
}else{
$('input[name='+driving_qs[i]+']').closest('.form-group').addClass('has-error');
$('input[name='+driving_qs[i]+']').closest('.form-group').removeClass('has-success');
}
}
var fields = [{
selector: $('.not-empty'),
validations: [ isNotEmpty]
},{
selector: $('.email'),
validations: [ isNotEmpty, isEmail]
},{
selector: $('.number'),
validations: [ isNotEmpty, isNumber]
},{
selector: $('.number-noreq'),
validations: [isNumberNotRequired]
}];
$('.form-control').closest('div').removeClass('has-error');
var i = 0, k = 0, z = 0, j = fields.length, item, selector, fn, info;
for(; i < j; i++){
item = fields[i];
for(k = 0; k < item.validations.length; k++){
fn = item.validations[k];
for( z = 0; z < item.selector.length; z++){
selector = $(item.selector[z]);
info = selector.closest('div');
if(info)
var result = fn(selector.val());
if(result){
info.removeClass("has-error");
info.addClass('has-success');
}else{
info.removeClass('has-success');
info.addClass("has-error")
}
}
}
}
}
The script works perfectly fine if I am running it without the for loop in front of it. Here is a quick step by step of what my code does (note: this is without the for loop):
Locate the section in code and find each input an select field
Assign the change event to each target input and select field
On change find closest span of class placement, and fine the first module heading and perform all the adding and removing of classes, just to refresh the heading to a success heading if no errors exist below.
Find all the inputs and selects and check for errors, if they exists return false, and add the error classes back on everything
This script will work all the way to the end of each section like it is supposed to do. However after I tried to do this with the for loop, it created a success scenario after only one input. Why is this happening, and is it even possible to have this function inside a loop like I am currently doing?
Also below I have included samples of the html mark-up
<!-- this tag serves no purpose other than being a bookmark for scripting -->
<span class='placement'>
<!-- Section 1: General Information -->
<div id='general-heading' class='row module-heading module-heading-bad general' data-toggle='#general_info'>
<div class='form-group'>
<div class='col-md-12'>
<h4 class='text-info '>General Information<div id='general-confirmation' class='glyphicon glyphicon-warning-sign pull-right text-danger'></div></h4>
</div>
</div>
</div>
<div id='general_info' class='app-section'>
<div class='form-group'>
<div class='col-xs-12'>
<div class='form-group row'>
<div class='col-sm-6 col-xs-12'>
<label class='control-label'>First Name<span class='req'> *</span></label><br />
<input type='text' class='form-control not-empty' id='first_name' value="<?=$first_name?>"/>
</div>
<div class='col-sm-6 col-xs-12'>
<label class='control-label'>Middle Name</label><br />
<input type='text' class='form-control' id='middle_name' value="<?=$middle_name?>"/>
</div>
</div>
</div>
</div>
</span>
The problem in this block of code:
for(var i = 0; i < sections.length; i++){
$(sections[i]).find('input, select').each(function(){
$(this).change(function(){
...
$(sections[i]).find('input, select').each(function(){
...
}
});
});
});
}
Is that it uses the variable i, which will have changed when the function() inside change is run.
In your case, the simplest way to fix it would be by using the forEach function instead of a for loop, and not using the index at all:
sections.forEach(function(section){
$(section).find('input, select').each(function(){
$(this).change(function(){
...
$(section).find('input, select').each(function(){
...
}
});
});
});
})
This will ensure that the i you mean is different each time.
I have a row of text boxes , I have a function to clone them based on what number comes into the function. So if there are going to be 4 users then I want the row to clone 4 times to enter the information of the 4 users. But I also want some way to be able to submit this form , I am having trouble figuring out how to give each row a unique class or id for each text box so I can read through them when submitting.
I was thinking adding "1" to each class (or id) to everything in the first row, then "2" to everything in the second. But I am not too sure as to how to do this. I have an example Here In jsFiddle , Since I have tried to add the for loop and clone a certain amount of times , now the clone isn't even working at all- If anyone has any suggestions , it would really help me out.
<div class="RegisterContainer">
<div class="RegisterHead"><a>Register Attendees</a></div>
<div class="placenewrows"></div>
</div>
<br />
<input type="button" onclick="fnCloneTemplate({'number' : '3'});" value="make 3 rows">
<div class="_template">
<a class="left1">First Name:</a>
<a class="left2"></a><a class="left2">Last Name:</a>
<a class="left3">Phone #</a><a class="left4">Email:</a>
<a class="left5">Optional Comment</a><br />
<input type="text" class="tFirstName left1"/>
<input type="text" class="tLastName left2"/>
<div class="phonenumberbox left3">
<input type="text" class="first3digits" maxlength="3" />
<a style="position:relative;top:-1px;">-</a>
<input type="text" class="next3digits" maxlength="3" />
<a style="position:relative;top:-1px;">-</a>
<input type="text" class="last4digits" maxlength="4" />
</div> <input type="text" class="tEmail left4"/>
function fnCloneTemplate(x){
var NumofClones = (x.number * 1);
for(i=0; i <= NumofClones; i++)
{
var newrow = $('._template').clone().removeclass('_template');
$('.placenewrows').append(newrow);
}
}
There is a typo in your code:
var newrow = $('._template').clone().removeclass('_template');
//----^
removeclass should be removeClass.
http://jsfiddle.net/y543n/
Also you haven't loaded jQuery in your fiddle and there is a scoping issue there, you are using HTML onclick attribute and your function in that context is not defined. You can use jQuery click method instead:
$('input[type=button]').click(function(e){
e.preventDefault();
// ....
})
$('input[type=button]').click(function(e) {
var numofClones = 3;
e.preventDefault();
var b = $('.placenewrows input[type=text]').length;
var newrow = $('._template').clone().removeClass('_template').find('input[type=text]').addClass(function(i, cur) {
return 'something' + ++b
}).end()
for (i = 0; i < numofClones; i++) {
$('.placenewrows').append(newrow);
}
})
http://jsfiddle.net/bgCXX/
You can change your function like below, to avoid multiple time cloning.
function fnCloneTemplate(e){
var NumofClones = (e.data.number * 1),
newrow= $('._template').clone().removeClass('_template'); // in your code
// removeClass spelling
// mistaken
for (i=0; i<NumofClones; i++)
{
$('.placenewrows').append(newrow);
}
}
Using on():
HTML
<input type="button"value="make 3 rows" id="make_clone">
jQuery
function fnCloneTemplate(e){
var NumofClones = (e.data.number * 1),
newrow= $('._template').clone().removeClass('_template');
for (i=0; i<NumofClones; i++)
{
$('.placenewrows').append(newrow);
}
}
$('#make_clone').on('click',{'number' : '3'}, fnCloneTemplate);
THE DEMO
Full Code for clone and unique class
function fnCloneTemplate(x) {
var NumofClones = (x.data.number * 1),
clone = $('._template').clone().removeClass('_template');
for (i = 0; i <= NumofClones; i++) {
var newrow = clone
.find('input[type=text]')
.attr('class', function(i, oldClass) {
return oldClass.replace(/\d/, function(char) {
return +char + i ;
});
return newClass
})
.end();
$('.placenewrows').append(newrow);
}
}