I have a form (commonStuff) cloned this way (and an html page, designed in jquery mobile, where the form appears multiple times, cloned):
var commonClone = commonStuff.cloneNode(true);
and this function
function renameNodes(node) {
var i;
if (node.length) {
for (i = 0; i < node.length; i += 1) {
renameNodes(node[i]);
}
} else {
// rename any form-related elements
if (typeof node.form !== 'undefined') {
node.id = currentPrefix + '_' + node.id;
node.name = currentPrefix + '_' + node.name;
// This assumes that form elements do not have child form elements!
} else if (node.children) {
renameNodes(node.children);
}
}
}
which add a prefix 'form1_', 'form_2' (the currentPrefix) to id and names of any element in the form and is applied to commonClone (and so recursively to his sons).
renameNodes(commonClone);
It work perfectly in case of text inputs like
<div data-role="fieldcontain" class="ui-field-contain ui-body ui-br">
<label for="foo" class="ui-input-text">Age:</label>
<input type="text" name="age" id="age" value="" class="ui-input-text ui-body-c ui-corner-all ui-shadow-inset">
</div>
But it fails on radio buttons like
<div data-role="fieldcontain">
<fieldset data-role="controlgroup" data-type="horizontal">
<legend>Address:</legend>
<input type="radio" name="radio-address" id="radio-address_female" value="1" checked="checked" />
<label for="radio-address_female">Address 1</label>
<input type="radio" name="radio-address" id="radio-address_male" value="2" />
<label for="radio-address_male">Address 2</label>
</fieldset>
</div>
applying the renaming to the outer divs like 'fieldcontain' and 'controlgroup'. It works if i remove those two divs but the graphical effect is unacceptable...
As far as now, i got the problem is in the last 'else if' block for it doesn't care of siblings, but I don't really know how to fix this. Any idea?
EDIT: This code comes from this answer How to create a tabbed html form with a common div
As you use jQuery mobile, jQuery will be available.
I hope this code will point you in the right direction:
var i = 0;
$("form").each(function() {
$(this).find("input, select").each(function() {
$(this).attr("id", "form" + i + "_" + $(this).attr("id"));
$(this).attr("name", "form" + i + "_" + $(this).attr("name"));
});
$(this).find("label").each(function() {
$(this).attr("for", "form" + i + "_" + $(this).attr("for"));
});
i++;
});
EDIT:
I understand your current approach fails with labels. Consider to wrap your input elements inside the label tag. In that case, you won't need the for-attribute. This is in accordance with the docs: http://api.jquerymobile.com/checkboxradio/
Consider this:
HTML
<form>
<div data-role="fieldcontain">
<fieldset data-role="controlgroup" data-type="horizontal">
<legend>Address:</legend>
<label><input type="radio" name="radio-address" id="radio-address_female" value="1" checked="checked" />Address 1</label>
<label><input type="radio" name="radio-address" id="radio-address_male" value="2" />Address 2</label>
</fieldset>
</div>
<div data-role="fieldcontain" class="ui-field-contain ui-body ui-br">
<label><input type="text" name="age" id="age" value="" class="ui-input-text ui-body-c ui-corner-all ui-shadow-inset">Age:</label>
</div>
</form>
jQuery
var i = 0, currentPrefix = "form";
$("form").each(function() {
$(this).find("input, select").each(function() {
$(this).attr("id", currentPrefix + i + "_" + $(this).attr("id"));
$(this).attr("name", currentPrefix + i + "_" + $(this).attr("name"));
});
i++;
});
Workin fiddle: https://jsfiddle.net/EliteSystemer/8sx6rnwo/
Truly, this is far from elegant, but a solution, anyway. In any node, this searches manually for input and labels, changing id, names and 'for' attribute in case of labels.
function renameNodes(node) {
var i;
if (node.length) {
for (i = 0; i < node.length; i += 1) {
renameNodes(node[i]);
}
} else {
// rename any form-related elements
if (typeof node.form !== 'undefined') {
node.id = currentPrefix + '_' + node.id;
node.name = currentPrefix + '_' + node.name;
var inputs = node.getElementsByTagName('input');
for (i = 0; i < inputs.length; ++i) {
inputs[i].id = currentPrefix + '_' + inputs[i].id;
inputs[i].name = currentPrefix + '_' + inputs[i].name;
}
var labels = node.getElementsByTagName('label');
for (i = 0; i < labels.length; ++i) {
labels[i].setAttribute('for', currentPrefix + '_' + labels[i].getAttribute("for"));
}
} else if (node.children) {
renameNodes(node.children);
}
}
}
Related
I am trying to count how many checkboxes the user checked so I could disable the other input so it will enter the database. How can I run on different elements $(" . ") using an array of different classes because I have a few groups of inputs in my form.
<script>
var countChecked = function() {
var n = $( ".neutral:checked" ).length;
alert( n + (n === 1 ? " is" : " are") + " checked!" );
};
countChecked();
$( "input[type=checkbox]" ).on( "click", countChecked );
</script>
// Count ALL checked boxes.
console.log($(":checked").length)
// Count checkboxes for a set of given classes.
console.log($(".one, .two, .three, .four").filter(":checked").length)
// Or given as array
let targets = [".one", ".two", ".three", ".four"];
console.log($(targets.join(",")).filter(":checked").length)
// or without the dot
targets = ["one", "two", "three", "four"];
console.log($(targets.map(x => `.${x}`).join(",")).filter(":checked").length)
// or if you want to do something separately for each class
const handleCheckboxes = (cls) => {
var n = $(`.${cls}:checked`).length;
console.log(`${n} of class ${cls} ${n === 1 ? "is" : "are"} checked!`);
// do even more stuff here
};
targets.forEach(handleCheckboxes);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="one" type="checkbox" checked>
<input class="two" type="checkbox" checked>
<input class="two" type="checkbox" checked>
<input class="two" type="checkbox" checked>
<input class="three" type="checkbox">
<input class="three" type="checkbox">
<input class="four" type="checkbox" checked>
<input class="four" type="checkbox">
You can simply loop through all classes
//Array
var array = ["class1", "class2", "class3", "class4", "class5"];
//Loop
array.forEach((className, classIndex) => {
var n = $('.' + className + ':checked').length;
var term = n === 1 ? "is" : "are";
console.log(n + ' of ' + className + term + ' checked');
});
I'm using Bootstrap Switch
to customize my checkboxes. In the documentation they suggest using:
$("[name='my-checkbox']").bootstrapSwitch();
So in my case I have multiple checkboxes so I did this:
var name = '"' + "[name='my-checkbox" + records[i].id + "']" + '"';
$(name).bootstrapSwitch();
But I get an error: Unrecognized expression: "[name='my-checkbox1']"
Remove extra "
var name = '[name="my-checkbox' + records[i].id + '"]';
Example
var records = [
{id: '-one'},
{id: '-two'}
];
var name;
for (var i = 0, len = records.length; i < len; i++) {
name = '[name="my-checkbox' + records[i].id + '"]';
console.log($(name));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input name="my-checkbox-one" type="checkbox">
<input name="my-checkbox-two" type="checkbox">
You do not need that much coding... If you add a class to you checkbox <input name="my-checkbox" class="nice-switch" type="checkbox">you can then activate the switch using $(".nice-switch").bootstrapSwitch();
Each time a new div is created via a button click, I want to dynamically keep an order so when one div is created it becomes 1 of 1, then 1 of 2 when a further div is created and when a div is deleted it reverts back to 1 of 1 etc.
I've tried using each to update all specific tags, but they do not update themselves each time a new div is added. This is the code:
iadd = 0;
itotal = 0;
$('#add').click(function() {
iadd++;
$('<div class="input-group col-sm-offset-4 col-sm-3" name="music" id="music' + iadd + '"><label for="phone" class="control-label"><b>Track ' + iadd + ' of ' + itotal + '</b></label><input type="text" class="form-control" name="music1" placeholder="Email" value="" id="music1" data-name="musicAdd" /><br><input type="text" class="form-control" name="email2" placeholder="Description" value="" id="music2" data-name="emailDesc"/></div>').appendTo('#musics');
$('.control-label').each(function() {
itotal = iadd;
});
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type="button" id="add">Add</button>
<div class="form-group" id="musics"></div>
How could it be possible to enable this? This is the JSFiddle
I would go like this:
$(function () {
$('#add').on('click', function () {
// The total is the number of divs within the main container + 1.
// + 1 because we're calculating it before actually appending the new one.
var total = $('#musics div').length + 1;
// The current index is exactly the total (you could save a variable here).
var index = total;
// Create the new div and append it to the main container.
var newDiv = $('<div class="input-group col-sm-offset-4 col-sm-3" name="music" id="music' + index + '"><label for="phone" class="control-label"><b>Track ' + index + ' of ' + total + '</b></label><input type="text" class="form-control" name="music1" placeholder="Email" value="" id="music1" data-name="musicAdd" /><br><input type="text" class="form-control" name="email2" placeholder="Description" value="" id="music2" data-name="emailDesc"/></div>').appendTo('#musics');
// Loop through the new div siblings (filtering the type just to make sure),
// and update their labels with the index/total.
newDiv.siblings('div').each(function (ix, el) {
$('label', el).html('<b>Track ' + (ix + 1) + ' of ' + total + '</b>');
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="add">Add</button>
<div class="form-group" id="musics"></div>
Demo (jsFiddle)
...
If you want to go a bit further (with some prototype):
// The explanation for the code below is basically the same you can
// find in the code above, with the exception of using prototype
// to create a format method, where you replace items within a string.
String.prototype.format = function () {
var value = this.toString();
for (var i = 0, len = arguments.length; i < len; i++) {
value = value.replace(new RegExp('\{[' + i + ']\}', 'g'), arguments[i]);
}
return value;
}
String.format = function () {
if (arguments.length == 0) return '';
var value = arguments[0].toString();
for (var i = 1, len = arguments.length; i < len; i++) {
value = value.replace(new RegExp('\{[' + (i - 1) + ']\}', 'g'), arguments[i]);
}
return value;
}
$(function () {
$('#add').on('click', function () {
var total = $('#musics div').length + 1;
var index = total;
var labelHtml = '<b>Track {0} of {1}</b>';
var newDiv = $('<div class="input-group col-sm-offset-4 col-sm-3" name="music" id="music{0}"><label for="phone" class="control-label">' + labelHtml.format(index, total) + '</label><input type="text" class="form-control" name="music1" placeholder="Email" value="" id="music1" data-name="musicAdd" /><br><input type="text" class="form-control" name="email2" placeholder="Description" value="" id="music2" data-name="emailDesc"/></div>'.format(index)).appendTo('#musics');
newDiv.siblings('div').each(function (ix, el) {
$('label', el).html(labelHtml.format((ix + 1), total));
});
});
});
Demo
...
UPDATE
As per your comment, I believe you're planning to have a delete button to be able to remove tracks and then update the indexes/total.
You can do it like this:
$(function () {
// A single function to update the tracks indexes/total.
function sortTracks() {
// Not like the first piece of code in the beginning of the answer,
// here we don't add 1 to the length, because the elements will be
// already in place.
var $tracks = $('#musics .input-group');
var total = $tracks.length;
$tracks.each(function (ix, el) {
$('label', el).html('<b>Track ' + (ix + 1) + ' of ' + total + '</b>');
});
}
$('#add').on('click', function () {
var index = $('#musics div').length + 1;
$('<div class="input-group col-sm-offset-4 col-sm-3" name="music" id="music' + index + '"><label for="phone" class="control-label"></label><input type="text" class="form-control" name="music1" placeholder="Email" value="" id="music1" data-name="musicAdd" /><br><input type="text" class="form-control" name="email2" placeholder="Description" value="" id="music2" data-name="emailDesc"/><button class="delete">Delete</button></div>').appendTo('#musics');
sortTracks();
});
$('#musics').on('click', '.delete', function () {
// Remove this element's immediate parent with class = input-group.
$(this).closest('.input-group').remove();
sortTracks();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="add">Add</button>
<div class="form-group" id="musics"></div>
Demo (jsFiddle)
Note: If you check your HTML string used to create the tracks, you'll notice that your inputs have hard-coded ids, so you'll have multiple elements sharing the same id, which is wrong. IDs should be always unique.
I'm using Eric Hynds jQuery MultiSelect Widget that is being populated from a javascript file. The issue is that either selection adds to both sides. Option 1-3 should only add to Main1-3, same for option/Main 4-6. Please see my fiddle of how it works and the issue http://jsfiddle.net/3u7Xj/112/
I think it would be eaisiest to break it out something like
var lbl = $("#MDCselect").val();
if (number1.checked) {...
('.holder').append...
var lbl2 = $("#ClinicalSelect").val();
if (number2.checked) {...
('.holder2').append...
currently
$(document).ready(function () {
$(".multiselect").multiselect({
header: "Choose up to 5 areas total",
click: function (event, ui) {
var number1 = $("#MDCselect").children(":checked").length,
number2 = $("#Clinicalselect").children(":checked").length;
if (ui.checked && ((number1 + number2 >= 5) || $(this).children(":checked").length >= 5)) {
return false;
}
var lbl = ui.value;
if (ui.checked) {
var ctrl = '<input type="checkbox" name="chk" checked="checked" class="chk" id="' + lbl.replace(/[^a-z0-9\s]/gi, '').replace(/[,\s]/g, '') + '">';
$("[id^=id]:checked").each(function () {
$(this).nextAll('.holder:first').append('<div>' + ctrl + lbl + '</div>');
});
} else {
$("[id^=id]:checked").each(function () {
$(this).nextAll('.holder:first').find('#' + lbl.replace(/[^a-z0-9\s]/gi, '').replace(/[,\s]/g, '')).parent().remove();
})
}
},
selectedList: 5
});
$(".checkers").click(function () {
if (!$(this).is(':checked')) {
$(this).nextAll('.holder:eq(0)').find('div input').parent().remove();
} else {
var checkedOnes = $('#MDCselect').nextAll('.ui-multiselect-menu').find('ul li input:checked');
$(".holder").html("");
for (var i = 0; i < checkedOnes.length; i++) {
var lbl = checkedOnes.eq(i).attr('value');
var ctrl = '<input type="checkbox" name="chk" checked="checked" class="chk" id="' + lbl.replace(/[^a-z0-9\s]/gi, '').replace(/[,\s]/g, '') + '">';
$("[id^=id]:checked").each(function () {
$(this).nextAll('.holder:first').append('<div>' + ctrl + lbl + '</div>');
});
}
}
});
});
I'm not entirely sure if I get what you want to do, try this and let me know if it is what you want, here is the fiddle if you want to try it http://jsfiddle.net/8xBcd/
I put the mains in a containing div, that way is easier to make selectors for the diferent mains. check the fiddle please.
<div id="main1-3" >
<input type="checkbox" name="chk1" value="Main1" id="id1" class='checkers'/><label for="Main1"><b>Main1</b></label>
<div class="holder"></div>
</br>
<input type="checkbox" name="chk2" value="Main2" id="id2" class='checkers'><label for="Main2"><b> Main2</b></label>
<div class="holder"></div>
</br>
<input type="checkbox" name="chk3" value="Main3" id="id3" class='checkers'><label for="Main3"><b> Main3</b></label>
<div class="holder"></div>
</div>
<select id="MDCselect" multiple="multiple" class="multiselect">
<option>1</option>
<option>2</option>
<option>3, this space</option>
</select><br>
I have a main div and inside of this, there are a lot of input text and radio button.
Like this:
<div id="mainDiv">
<input type="text" name="text-1" /> <br/>
<input type="radio" name="radio-1" />Yes
<input type="radio" name="radio-1" />No <br/>
<input type="text" name="text-2" /> <br/>
<input type="text" name="text-3" /> <br/>
</div>
<img src="img/img.gif" onclick="getAllValues();" />
I want to define the function getAllValues() in jQuery to get all values in mainDiv and save them in a string.
It is possible?
To achieve this you can select all the form fields and use map() to create an array from their values, which can be retrieved based on their type. Try this:
function getAllValues() {
var inputValues = $('#mainDiv :input').map(function() {
var type = $(this).prop("type");
// checked radios/checkboxes
if ((type == "checkbox" || type == "radio") && this.checked) {
return $(this).val();
}
// all other fields, except buttons
else if (type != "button" && type != "submit") {
return $(this).val();
}
})
return inputValues.join(',');
}
The if statement could be joined together here, but I left them separate for clarity.
Try something like that:
function getAllValues() {
var allVal = '';
$("#mainDiv > input").each(function() {
allVal += '&' + $(this).attr('name') + '=' + $(this).val();
});
alert(allVal);
}
Here is solution which is building you a JSON string. It's getting the values of the text fields, check boxes and select elements:
function buildRequestStringData(form) {
var select = form.find('select'),
input = form.find('input'),
requestString = '{';
for (var i = 0; i < select.length; i++) {
requestString += '"' + $(select[i]).attr('name') + '": "' +$(select[i]).val() + '",';
}
if (select.length > 0) {
requestString = requestString.substring(0, requestString.length - 1);
}
for (var i = 0; i < input.length; i++) {
if ($(input[i]).attr('type') !== 'checkbox') {
requestString += '"' + $(input[i]).attr('name') + '":"' + $(input[i]).val() + '",';
} else {
if ($(input[i]).attr('checked')) {
requestString += '"' + $(input[i]).attr('name') +'":"' + $(input[i]).val() +'",';
}
}
}
if (input.length > 0) {
requestString = requestString.substring(0, requestString.length - 1);
}
requestString += '}';
return requestString;
}
You can call the function like this:
buildRequestStringData($('#mainDiv'))
And the result http://jsfiddle.net/p7hbT/