After deleting middle input renumber data-id - javascript

Right now when you add inputs they are numbered 1 by 1 so let's say we add 5 champions they will be numbered like
1
2
3
4
5
And let's say we want to remove 3rd one it will look like
1
2
4
5
And I want i to be numbered after removing like
1
2
3
4
Here is a working http://jsfiddle.net/dyje773m/ and also http://89.69.172.125/cms2.0/
Most important part of the code:
$(document).ready(function(){
championNumberArray = 0;
championNumber = 1;
$('a#AddChampion').on('click',function(){
$('div#ChampionInput').append(
'<div class="Champion" data-id="'+championNumberArray+'">\
Remove\
<br>\
<input type="text" class="ChampionInput" list="champions" name="champion[]" placeholder="Champion '+championNumber+'">\
<datalist id="champions"></datalist>\
Add Spell\
Add General Change\
<div class="GeneralChanges">\
</div>\
<div class="SpellChanges">\
</div>\
<br>\
<div>');
for(var key in champions){
if(champions.hasOwnProperty(key)){
$('#champions').append('<option value="' + key + '">');
}
}
championNumberArray++;
championNumber++;
});
});
And index
<div id="wrap">
Add Champion
<form name="second_form" id="second_form" method="POST">
<div id="ChampionInput">
</div>
<br><br>
<input type="submit" name="submit">
</form>
</div>

you shouldn't use championNumberArray and championNumber to store inputs quantities, instead of that u should count all the divs with class 'Champion' to get current quantity.
$("div.Champion").length;
when a input is added, u should set "id" value using previous method above.
when a input is deleted, u should get ther "id" value before removing... after removed, u can do following (( supposing "3" was removed ))
var c=3-1, el;
while(el=$("div.Champion:eq("+c+")").get())
{ $(el).data("id",c+1); c++; }

You have to renumber the inputs when you remove one. Try something like below.
$('div#ChampionInput').on('click', 'a.Remove',function(){
var champion = $(this).closest('.Champion');
var id = champion.data("id");
var nextChampion = champion;
//
// Loop through each following champion
while((nextChampion = nextChampion.next()).length != 0){
// Update id
nextChampion.attr("data-id",id++)
// Update placeholder
// Placeholder is id + 1 because placholders start at 1 and ids start at 0
nextChampion.find(".ChampionInput").attr("placeholder","Champion " + (id + 1));
}
// Remove champion
champion.remove();
});
By the way, you don't need to have the tagname before the selector. Especially for ids, which should be unique per page. #ChampionInput is exactly like div#ChampionInput, except #ChampionInput is faster because the browser doesn't have to check if the tagName matches.

Related

Generate Dynamic Inputs with Unique Names in jQuery

In my HTML form, it's possible to add additional inputs dynamically by clicking a button. I've got this part to work, however I need each input to have a unique name.
This is my code so far,
<div class="control-group field_wrapper">
<label class="control-label"><strong> Phone Number 1</strong></label>
<input type="text" class="input-medium" name="phone_number[]">
<button class="btn btn-success add-number" type="button" title="Add">Add</button>
</div>
<div class="additionalNumber"></div>
My JS as below,
$(document).ready(function(){
var maxField = 10;
var addButton = $('.add-number');
var wrapper = $('.additionalNumber');
function fieldHTML(inputNumber) {
return `<div class="control-group field_wrapper">\
<label class="control-label"><strong> Phone Number ${inputNumber}</strong></label>\
<input type="text" class="input-medium" name="phone_number[${inputNumber}]">\
<button class="btn btn-danger remove" type="button">Remove</button>\
</div>`;
}
var x = 1;
$(addButton).on('click', function(e) {
if (x < maxField) {
x++;
$(wrapper).append(fieldHTML(x));
}
if (x >= maxField) {
alert('Limited to 10.');
}
});
$(wrapper).on('click', '.remove', function(e) {
e.preventDefault();
$(this).parents('.control-group').remove();
x--;
});
});
Using this code, I can get unique name for each input which are created by dynamically. But my problem is name[x] index not works properly when it is removing. That mean, just think I have added 3 input and delete second one and again I am adding new one, then it has same name twice. In this case, it is phone_number[3] for second input and phone_number[3] for thirt one also.
This is the fiddle from above code. Any help is appreciated.
You don't need to index the inputs for PHP either - 3x inputs named phone_number[] will automatically be indexed 0 - 2 on the back end:
<input type="text" name="phone_number[]">
<input type="text" name="phone_number[]">
<input type="text" name="phone_number[]">
[phone_number] => Array
(
[0] => a
[1] => b
[2] => c
)
That doesn't help with your plain text Phone Number n label though. And maybe you have your own reasons to want an input name index.
If you think about it, if you're going to allow deletions of any item in the list, and you need the results to be sequential, the only option is to renumber everything each time you make a change. You don't need to include any numbering when you add a new element, just regenerate all numbering.
Here's a working snippet doing that. My changes:
No need to pass the count x to fieldHTML(), we're going to renumber everything after you add the element;
Add a <span class='count'></span> in your label, which we can target and update;
Add a reNumber() function which will iterate over all inputs on the page and number them sequentially;
Call that function after any change;
Notes:
The 2 separate tests if (x < maxField) and if (x >= maxField) can be combined into a single if/else;
If you want to get rid of the duplication of your HTML block, you could give the first one an id like template, and then instead of duplicating that HTML in your JS, just copy the template, eg :
let $copy = $('#template').clone();
wrapper.append($copy);
wrapper and addButton are already jQuery objects, no need to wrap them with $() a second time to use them;
If you do want to number your input names, for consistency the first should probably be phone_number[1];
$(document).ready(function() {
var x = 1;
var maxField = 10;
var addButton = $('.add-number');
var wrapper = $('.additionalNumber');
function fieldHTML() {
return `<div class="control-group field_wrapper">\
<label class="control-label"><strong> Phone Number <span class='count'></span></strong></label>\
<input type="text" class="input-medium" name="phone_number[]">\
<button class="btn btn-danger remove" type="button">Remove</button>\
</div>`;
}
/**
* Iterate over all inputs and renumber sequentially
*/
function reNumber() {
let count;
wrapper.find('.field_wrapper').each(function (i) {
// .each() index is 0-based, and input #1 is already on the page,
// so extras start at #2
count = i + 2;
$('.count', $(this)).html(count);
// If you want to index your input names, but you can safely leave
// this out, PHP will index them anyway
$('input', $(this)).attr('name', 'phone_number[' + count + ']')
});
}
addButton.on('click', function(e) {
if (x < maxField) {
x++;
wrapper.append(fieldHTML());
reNumber();
} else {
alert('Limited to 10.');
}
});
wrapper.on('click', '.remove', function(e) {
e.preventDefault();
$(this).parents('.control-group').remove();
x--;
reNumber();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="control-group field_wrapper">
<label class="control-label"><strong> Phone Number 1</strong></label>
<input type="text" class="input-medium" name="phone_number[]">
<button class="btn btn-success add-number" type="button" title="Add">Add</button>
</div>
<div class="additionalNumber"></div>

javascript copy (duplicate) text from 1 field to another

i have 20 fields
10 with name= from 1 to 10
and 10 fields with same name from 1 to 10
<input name="1" type="text">
...
<input name="10" type="text">
and 10 fields like this
<input name="1" type="text">
...
<input name="10" type="text">
so what i want is: to write in first 10 fields , and other 10 to be filled automatically
i can change names to id or add prefix to id of second group.
or its better with names .
if u change names to id 1-10 then second group id a1-a10
function populateSecondTextBox() {
document.getElementById('1').value = document.getElementById('a1').value;
}
this is for 1 only,
someone can add answer for doing all with 1 code
you want to mirror the changes like this ?
for(let i=1; i<11 ; i++){
let input = document.getElementsByName(i.toString())[0];
let mirror = document.getElementsByName(i.toString())[1];
input.onkeyup=()=>{ mirror.value = input.value; }
}

javascript modify variable

I have this:
var category = "3%2C16%2C6%2C10%2C1%2C19";
in witch category id are 3 16 6 10 1 19 and the %2C is the space between category.
What i want is here:
if (document.getElementById("3").checked = false) {
category = "16%2C6%2C10%2C1%2C19";
}
else {
category = "3%2C16%2C6%2C10%2C1%2C19";
}
I want to make this for all the checkbox that i have, but you can't deselect all the checkbox because the servers don't send you back any data.
This is for filtering the results
It would be easier to use an array, then convert it to this string representation, when needed.
var categories = [];
$('#category-form input').change(function () {
var id = $(this).attr('data-id'),
index = categories.indexOf(id);
if (this.checked && index === -1) {
categories.push(id);
} else if (!this.checked && index !== -1) {
categories.splice(index, 1);
}
});
You can see my working code in this fiddle.
(with multiple checkboxes, string representation, and at least one check)
Try
if (document.getElementById("3").checked === false) {
notice the extra double equals to do a typesafe check
or better still
if (!document.getElementById("3").checked) {
However, as you're using jQuery and you appear to be munging a string together from checked states, which is going to be really brittle with hardcoded strings so maybe something like:
var category = "";
$( "input:checked" ).each(function() {
category = $(this).id + "%2C";
};
Only calling that when you need the output e.g. button press.
As you are using jquery, you can listen to the change event for the checkboxes, then build the list each time one is checked or unchecked. To store the values you can either use the value attribute for the checkbox or add data- attributes.
Getting an array of values and joining them will avoid the trailing %2C.
var category = '';
(function($) {
// cache collection of checkboxes
var cboxes = $('input[type=checkbox]');
cboxes.on('change', function() {
// find the ticked boxes only, and make an array of their category values, then join the values by a space
category = $.makeArray(cboxes.filter(':checked').map(function() {
return $(this).data('category');
//return $(this).val(); // if you store them in value="3"
})).join('%2C');
// output for debug purpose
$('#categoryOutput').html("'" + category + "'");
});
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<form>
<input type="checkbox" id="c1" data-category="3" />
<input type="checkbox" id="c2" data-category="16" />
<input type="checkbox" id="c3" data-category="6" />
<input type="checkbox" id="c4" data-category="10" />
<input type="checkbox" id="c5" data-category="1" />
<input type="checkbox" id="c6" data-category="19" />
</form>
<div id="categoryOutput"></div>
Side Note: try to avoid starting element ids with numbers - it is technically invalid and can break things in some scenarios.

create an infinitely extensible form?

I have a form that needs to be able to multiply specific lines in the form, as well as then duplicate the entire form. In the concept example I am working on, there is a Name field, and a URL field. I need 1 name field, and up to 3 URL fields, but then I need to duplicate this entire grouping up to 3 times, and submit it via POST, but the number pairings can be different.
As an example, the first group can have 1 name, 3 urls, the second have 1 url, and the third have 3 urls. I am able to multiply the number of URL fields, or the entire form, but if I have 2 URL fields, all multiples of the form have 2 URL fields, and I am then unable to change it in any of the forms.
Looking at the JSFiddle is much easier than just posting the code here, because you can see my code, as well as how it behaves.
http://jsfiddle.net/wingdom/yCTpf/3/
Thank you for the help!
HTML:
<form id="myForm">
<div id="O1" class="clonedInput5">
<fieldset>
<input type="hidden" name="Ocount" id="Ocount" value="1" />
<legend>Outbound App - Required</legend>
<div>
<label>Name:</label>
<input type="text" name="oname">
</div>
<div id="ourl1" style="margin-bottom:4px;" class="clonedInput1">URL:
<input type="text" name="ourl1" id="ourl1" />
</div>
<div>
<input type="button" id="ourlAdd" value="Add URL" />
<input type="button" id="ourlDel" value="Remove URL" />
</div>
<input type="hidden" name="urlo" id="urlo" value="1" />
</fieldset>
</div>
<input type="button" id="OAdd" value="Add Outbound" />
<input type="button" id="ODel" value="Rm Outbound" />
Javascript:
$('#ourlAdd').click(function () {
var num = $('.clonedInput1').length; // how many "duplicatable" input fields we currently have
var newNum = new Number(num + 1); // the numeric ID of the new input field being added
// create the new element via clone(), and manipulate it's ID using newNum value
var newElem = $('#ourl' + num).clone().attr('id', 'ourl' + newNum);
// manipulate the name/id values of the input inside the new element
newElem.children(':first').attr('id', 'ourl' + newNum).attr('name', 'ourl' + newNum);
// insert the new element after the last "duplicatable" input field
$('#ourl' + num).after(newElem);
document.getElementById("urlo").value = newNum;
// enable the "remove" button
$('#ourlDel').attr('disabled', '');
// business rule: you can only add 5 names
if (newNum == 3) $('#ourlAdd').attr('disabled', 'disabled');
});
$('#ourlDel').click(function () {
var num = $('.clonedInput1').length; // how many "duplicatable" input fields we currently have
$('#ourl' + num).remove(); // remove the last element
document.getElementById("urlo").value = num - 1;
// enable the "add" button
$('#ourlAdd').attr('disabled', '');
// if only one element remains, disable the "remove" button
if (num - 1 == 1) $('#ourlDel').attr('disabled', 'disabled');
});
$('#ourlDel').attr('disabled', 'disabled');
$('#OAdd').click(function () {
var num = $('.clonedInput5').length; // how many "duplicatable" input fields we currently have
var newNum = new Number(num + 1); // the numeric ID of the new input field being added
// create the new element via clone(), and manipulate it's ID using newNum value
var newElem = $('#O' + num).clone().attr('id', 'O' + newNum);
// insert the new element after the last "duplicatable" input field
$('#O' + num).after(newElem);
document.getElementById("Ocount").value = newNum;
// enable the "remove" button
$('#ODel').attr('disabled', '');
// business rule: you can only add 5 names
if (newNum == 3) $('#OAdd').attr('disabled', 'disabled');
});
$('#ODel').click(function () {
var num = $('.clonedInput5').length; // how many "duplicatable" input fields we currently have
$('#O' + num).remove(); // remove the last element
document.getElementById("Ocount").value = num - 1;
// enable the "add" button
$('#OAdd').attr('disabled', '');
// if only one element remains, disable the "remove" button
if (num - 1 == 1) $('#ODel').attr('disabled', 'disabled');
});
$('#ODel').attr('disabled', 'disabled');
One way of doing it would be to store a copy of the original form initially, then use that copy to create your additional forms.
var $originalForm = $("#originalForm").clone();
Now, any time you need to create a new form, you just do: $originalForm.clone() then iterate through the elements within the form fixing ID's (assuming you don't go away from using id's.)
Though, personally i would do this a completely different way.
var formTemplate = "form template here, or get it from a <script type=\"text/template\"></text>";
function ExtendableForm() {
this.$form = $(formTemplate).appendTo("body");
this.bindEvents();
return this.$form;
}
$.extend( ExtendableForm.prototype, {
addAnotherURL: function(){
this.$form.find(".wrap-url").append($(formTemplate).find(".wrap-url").children());
},
addAnotherName: function(){
this.$form.find(".wrap-name").append($(formTemplate).find(".wrap-url").children());
},
bindEvents: function(){
this.$form
.on("click", ".add-url", $.proxy(addAnotherURL,this))
.on("click", ".add-name", $.proxy(addAnotherName,this));
}
});
$("#addAnotherForm").click(function(){
$("#form-container").append(new ExtendableForm());
}).click();
It could probably be made a bit dryer, but that's the basic idea. No one form is aware of or needs to care about any other form.

Deleting any element, the reassigning the count value

Sorry about the cryptic title, it's hard to describe!
I am using the following script to add a row to my form when a button is clicked:
$(document).ready(function() {
$('#btnAdd').click(function() {
var num = $('.clonedInput').length;
var newNum = new Number(num + 1);
var newElem = $('#input' + num).clone().attr('id', 'input' + newNum);
newElem.children(':first').attr('id', 'name' + newNum).attr('name', 'name' + newNum);
$('#input' + num).after(newElem);
$('#btnDel').attr('disabled','');
if (newNum == 5)
$('#btnAdd').attr('disabled','disabled');
});
$('#btnDel').click(function() {
var num = $('.clonedInput').length;
$('#input' + num).remove();
$('#btnAdd').attr('disabled','');
if (num-1 == 1)
$('#btnDel').attr('disabled','disabled');
});
$('#btnDel').attr('disabled','disabled');
});
This works absolutely fine, but it's not very user-friendly that you can only delete the last added row. Say I want to delete a row added earlier on, I would have to delete everything I'd done since then.
How can I delete any row, and at the same time reassign the count value to the other rows, so that the count is still sequential (i.e. Row1, Row2, Row3 etc, rather than Row1, Row5, Row8)?
I recommend that you don't explicitly set an id to the elements. Instead you can use jQuery powerful selectors to get the position of an element.
This is an example, based on a common html structure. Post your own html to give you a more details.
$('.btnDel').click(function() {
var num = $(this).parent().prevAll().size();
// this points to delete link.
// The previous element is the content element
$(this).prev().remove();
$('#btnAdd').attr('disabled','');
if (num-1 == 1)
$(this).attr('disabled','disabled');
});
<div class='elem'>
<span class='content'>....</span>
<a class='btnDel' href='#'>Delete</a>
</div>
Why are you even adding IDs to the rows? Remember that 83% of jQuery is "Query" - use the selectors to get to the elements you want.
I had to do a similar thing a while ago
Essentially I got the number of the deleted row ie. Row3 and then looped through the remaining rows updating their values. so Row4 becomes Row3 etc.
I used something like this
var last_val = //get the last value of the rows so you know when to stop
//knock off the Row part of the id and parses as an integer
var pos = parseFloat(row_id.slice(3))
var next_val = position+1;
var prev_val = position;
while(next_val<=last_val){
next_selector = "#Row"+next_val;
prev_id = "Row"+prev_val;
$(next_selector).attr("id",prev_id);
next_val++;
prev_val++;
}
There may be a better way to do this, but this worked for me for a cms allowing pages to be deleted from the middle of a list which then updated the row numbering.
I posted a demo here (it doesn't look good in IE because of the float, but I just wanted to post this as an example to help). I don't know how you handle gathering your form data, so I did include renumbering the cloned input IDs.
CSS
form { width: 400px; margin: 0 auto; line-height: 30px; }
input { float: right; }
HTML
<form>
<div class="main">
Name: <input type="text" /><br>
Title: <input type="text" /><br>
Company: <input type="text" /><br>
Location: <input type="text" /><br>
</div>
Additional information: <input id="btnAdd" type="button" value="Add More"/>
<div id="addFields"></div>
</form>
Script
$(document).ready(function(){
$('#btnAdd').click(function(){
// inputs reversed because of the float right
var newInput = '<div class="clonedInput">Additional Field <span></span>: ' +
'<input type="button" class="btnDel" title="Delete this field" value="X"><input type="text" /></div>';
$(newInput).appendTo('#addFields');
// disable add button if there are 5 additional fields
if ($('.clonedInput').length == 5) {
$('#btnAdd').attr('disabled','disabled');
}
renumber();
})
// Delete input field
$('.btnDel').live('click',function(){
$('#btnAdd').attr('disabled','');
$(this).parent().remove();
renumber();
})
})
// This function adds the additional field number and ID for each clonedInput field
function renumber(){
$('.clonedInput').each(function(i){
$(this).find('span').html('#' + (i+1));
// the code below will change the ID of the input, in case you collect your data based on the ID.
$(this).find('input[type=text]').attr('id', 'input' + (i+1));
})
}

Categories

Resources