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>
Related
So I'm very new to the world of jQuery and while writing a simple code a faced a problem that I couldn't figure out the solution for.
First of all, there's a function that updates the position of the form on the dropdown according to its index.
And then there's another function that will change the position of the form on the page when a new position is selected on the dropdown list:
$(document).ready(initialRank);
function initialRank() {
var itemIndex = $(".template-detail-field").length;
$('.field-rank').each(function () {
$(this).empty();
var pos = $(".field-rank").index($(this))+1;
for (var i = 1; i <= itemIndex; i++) {
if (i == pos) $(this).append('<option value="'+ i +'" selected>' + i + '</option>');
else $(this).append('<option value="' + i + '">' + i + '</option>');
}
});
}
$(document).on("change", ".field-rank", function () {
$(".template-detail-field").each(function () {
var sel = $(this).find(".field-rank").val();
var pre = $(".template-detail-field").eq(sel - 1);
$(this).insertBefore(pre);
});
initialRank();
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="template-detail-field">
<p> Testing stuff 1 </p>
<select class="field-rank">
<option value="1" selected>1</option>
</select>
</div>
<div class="template-detail-field">
<p> Testing stuff 2 </p>
<select class="field-rank">
<option value="2" selected>2</option>
</select>
</div>
<div class="template-detail-field">
<p> Testing stuff 4 </p>
<select class="field-rank">
<option value="4" selected>4</option>
As you can see, after changing position I call the function initialRank() so that it updates the positions displayed for each form accordingly. The problem is after I do this, the dropdown list won't accept any input, and by that I mean when I choose a new position on the list the form doesn't change its position nor does the new chosen position is selected.
But when I rewrite the initialRank() code inside the change() function everything works fine:
$(document).ready(initialRank);
function initialRank() {
var itemIndex = $(".template-detail-field").length;
$('.field-rank').each(function () {
$(this).empty();
var pos = $(".field-rank").index($(this))+1;
for (var i = 1; i <= itemIndex; i++) {
if (i == pos) $(this).append('<option value="'+ i +'" selected>' + i + '</option>');
else $(this).append('<option value="' + i + '">' + i + '</option>');
} });
}
$(document).on("change", ".field-rank", function () {
$(".template-detail-field").each(function () {
var sel = $(this).find(".field-rank").val();
var pre = $(".template-detail-field").eq(sel - 1);
$(this).insertBefore(pre);
});
var itemIndex = $(".template-detail-field").length;
$('.field-rank').each(function () {
$(this).empty();
var pos = $(".field-rank").index($(this)) + 1;
for (var i = 1; i <= itemIndex; i++) {
if (i == pos) $(this).append('<option value="' + i + '" selected>' + i + '</option>');
else $(this).append('<option value="' + i + '">' + i + '</option>');
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="template-detail-field">
<p> Testing stuff 1 </p>
<select class="field-rank">
<option value="1" selected>1</option>
</select>
</div>
<div class="template-detail-field">
<p> Testing stuff 2 </p>
<select class="field-rank">
<option value="2" selected>2</option>
</select>
</div>
<div class="template-detail-field">
<p> Testing stuff 4 </p>
<select class="field-rank">
<option value="4" selected>4</option>
Can someone please explain to me what I was doing wrong.
Thank you.
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);
}
}
}
My fiddle is here: http://jsfiddle.net/6yb7cv5c/
Visit the above fiddle, and you will see in the "result" window (bottom right) that when you click the 3 dots it changes into a textbox, you click out and it changes into text again, but clicking it again to change it into a textbox gives this error:
Uncaught TypeError: Cannot read property 'style' of undefined
which is this line:
$(this).find("span")[0].style.display="none";
The problem is in the static markup(at the beginning) the em element has a span as its child inside which you have the content, but when you edit it you are not putting it back
$(".editINPUT").blur(function () {
$(this)[0].style.display = "none";
if ($(this)[0].value == "") {
$(this).prev()[0].innerHTML = "<span>...</span>";
} else {
$(this).prev().html($('<span />',{text:this.value}))
}
$(this).prev().show();
//var i = $(this)[0].attr("id");
var i = $(this)[0].id;
var ii = $(this)[0].value;
console.log(i + " " + ii + " " + $("#tempData").data("data"));
});
$(document).ready(function() {
$(".editDIV").dblclick(function() {
var $this = $(this),
text = $this.find('span').text();
$("#tempData").data("data", text);
$this.find("span").hide();
$this.find("input").val(text).show().focus();
});
$(".editINPUT").blur(function() {
var $this = $(this),
value = this.value;
$this.hide();
var $span = $('<span />', {
text: value == "" ? '...' : this.value
});
$this.prev().html($span).show();
//var i = $(this)[0].attr("id");
var i = this.id;
var ii = this.value;
console.log(i + " " + ii + " " + $("#tempData").data("data"));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="picFilename editDIV">
<em><span class="editESPAN" style="display:block;">...</span></em>
<input class="editINPUT" style="display:none;" type="text" id="2_1_c" />
</div>
<div class="picFilename editDIV">
<em><span class="editESPAN" style="display:block;">...</span></em>
<input class="editINPUT" style="display:none;" type="text" id="2_2_c" />
</div>
<div class="editDIV">
<span class="editESPAN" style="display:block;">asd</span>
<input class="editINPUT" style="display:none;" type="text" id="asdf1" />
</div>
<div class="editDIV">
<span class="editESPAN" style="display:block;">asd</span>
<input class="editINPUT" style="display:none;" type="text" id="asdf2" />
</div>
<div id="tempData"></div>
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 have a jsfiddle that replace a td value with a select with 2 values: http://jsfiddle.net/B47km/
When i click the td, the select appears, but when i'm going to see the option elements the click event of the td throws and i can't show the options. How can i solve this?
The HTML:
<table>
<td class="test">1</td>
</table>
The js code:
$(function () {
$(".test").click(function (e) {
e.stopPropagation();
var currentEle = $(this);
var value = $(this).html();
select = '<select class="select-dorsal form-control" type="text">'
+'<option name="1" value="1">1</option>'
+'<option name="2" value="2">2</option>'
+'</select>';
$(currentEle).html(select);
});
});
Fixed it for you http://jsfiddle.net/B47km/3/ This will replace the cell content just once not every time you click on it.
$(function () {
$(".test").click(function (e) {
var currentEle = $(this);
var value = $(this).html();
if ($(this).find('select').length === 0)
{
select = '<select class="select-dorsal form-control" type="text">'
+'<option name="1" value="1">1</option>'
+'<option name="2" value="2">2</option>'
+'</select>';
$(currentEle).html(select);
}
});
});
There's probably a better way (I am a bit rusty on JQuery) but
if (!$(e.target).hasClass('test')) {
return
}
To see if the click event came from the td or the select seems to fix the plnkr.
Use jQuery one() method , which will only listen the event once
$(function () {
$(".test").one('click',function (e) {
e.stopPropagation();
var currentEle = $(this);
var value = $(this).html();
select = '<select class="select-dorsal form-control" type="text">'
+'<option name="1" value="1">1</option>'
+'<option name="2" value="2">2</option>'
+'</select>';
currentEle.html(select);
});
});
Fiddle Demo
Although you've not said explicitly, I'm guessing you're trying to implement a click to change, select a new value and then put that back in (removing the select). In which case:
$(function () {
$('.test').click(function (e) {
var td = $(this);
var select = $(document.createElement('select')).attr('name', 'select_name').attr('class', 'select-dorsal form-control'),
curVal = parseInt(td.get('text'));
for(var i = 0; i <= 5; i++) {
select.append('<option value="' + i + '"' + (curVal == i ? ' selected="selected"' : '') + '>' + i + '</option>');
}
td.html(select);
select.on('click', function(e) { e.stopPropagation(); });
select.on('change', function(e) {
var newVal = parseInt(this.options[this.selectedIndex].value);
td.html(newVal);
});
});
});
http://jsfiddle.net/B47km/10/