I have some code which uses this to allow to keep the same function code but apply it to different form elements which can be seen on a jsFiddle demo
//latest
var maxFields = 10,
currentFields = 1;
$('.form').on('click', '.add', function () {
var value_src = $(this).prev();
var container = $(this).parent().prev();
if ($.trim(value_src.val()) != '') {
if (currentFields < maxFields) {
var value = value_src.val();
var html = '<div class="line">' +
'<input id="accepted" type="text" value="' + value + '" />' +
'<input type="button" value="X" class="remove" />' +
'</div>';
$(html).appendTo(container);
value_src.val('');
currentFields++;
} else {
alert("You tried to add a field when there are already " + maxFields);
}
} else {
alert("You didn't enter anything");
}
})
.on('click', '.remove', function () {
$(this).parents('.line').remove();
currentFields--;
});
My issue is that I still want to be able to limit each section to only have 10 <inputs>, but at the moment each section shares the counter, so 5 in requirements and 5 in qualifications would trigger the 10 limit.
Is there a nice clean way of keeping the input field counter separate for each section?
What you need to do is store the current number of children for each list in a context sensitive way. There are a couple ways you could structure this (it would be easy using MVC libraries or the likes), but the simplest solution for your code will be to just use the DOM. So instead of using your global currentFields variable, instead use container.children().length to get the number of notes in the list you are currently operating on.
http://jsfiddle.net/9sX6X/70/
//latest
var maxFields = 10;
$('.form').on('click', '.add', function () {
var value_src = $(this).prev();
var container = $(this).parent().prev();
if ($.trim(value_src.val()) != '') {
if (container.children().length < maxFields) {
var value = value_src.val();
var html = '<div class="line">' +
'<input id="accepted" type="text" value="' + value + '" />' +
'<input type="button" value="X" class="remove" />' +
'</div>';
$(html).appendTo(container);
value_src.val('');
} else {
alert("You tried to add a field when there are already " + maxFields);
}
} else {
alert("You didn't enter anything");
}
})
.on('click', '.remove', function () {
$(this).parents('.line').remove();
});
You can add a class to each row like form-row
var html = '<div class="line form-row">' +
'<input id="accepted" type="text" value="' + value + '" />' +
'<input type="button" value="X" class="remove" />' +
'</div>';
and count the length by using
console.log($(container).find('.form-row').length);
// Use +1 because initially it is 0
Fiddle http://jsfiddle.net/9sX6X/69/
You can make use of the placeholder property to identify which button triggered the function.
value_src.attr('placeholder');
This string can then be used to access three different counters in an associative array.
Code
var maxFields = 10;
var currentFields = new Object;
$('.form').on('click', '.add', function () {
var value_src = $(this).prev();
var container = $(this).parent().prev();
if ($.trim(value_src.val()) != '') {
var identity = value_src.attr('placeholder');
if(currentFields[identity] == undefined)
currentFields[identity] = 0;
if (currentFields[identity] < maxFields) {
var value = value_src.val();
var html = '<div class="line">' +
'<input id="accepted" type="text" value="' + value + '" />' +
'<input type="button" value="X" class="remove" />' +
'</div>';
$(html).appendTo(container);
value_src.val('');
currentFields[identity]++;
} else {
alert("You tried to add a field when there are already " + maxFields);
}
} else {
alert("You didn't enter anything");
}
})
.on('click', '.remove', function () {
$(this).parents('.line').remove();
currentFields--;
});
JSFiddle: http://jsfiddle.net/9sX6X/73/
Related
Here I attach the images where you can see the list of data which show after page load but in all rows but when i add the row using jquery it is not show the data. please check image 2
image first
image 2
This is the link of mtree demo and this is the codepen link
and below is the code that i use to generate row and display mtree.
$(document).ready(function() {
var ite = <?php echo $projectCount; ?>;
$('.btn-row-add').click(function() {
var leaveDays = checkLeaveDays();
console.log(leaveDays);
var ite2 = 1
style = '';
readOnly = '';
if(jQuery.inArray(ite2, leaveDays) !== -1){
style = "style = 'background:#00FF00;'";
readOnly = "readonly='readonly'";
}
var el2 = '<td><input '+style+' '+readOnly+' id="text_'+ite2+'" class="short-textbox" type="text" name="day_'+ite+'[]" value="" onkeyup="sumNewRows(), colsValues(), colsVertical()"></td>';
for(var i=2; i<<?php echo $noOfDays+1; ?>; i++) {
styleInner = '';
readOnlyInner = '';
if(jQuery.inArray(i, leaveDays) !== -1){
styleInner = "style = 'background:#00FF00;'";
readOnlyInner = "readonly='readonly'";
}
el2 = el2 + '<td><input '+styleInner+' '+readOnlyInner+' id="text_'+i+'" class="short-textbox" type="text" name="day_'+ite+'[]" value="" onkeyup="sumNewRows(), colsValues(), colsVertical()"></td>';
}
console.log($('whc-table tbody').html());
var el = '<tr id="data_'+ite+'">\n' +
'<th scope="row">\n' +
'<select class="dropdownlist" data-text-field="name" name="project_name[]" style="width: 300px;">\n' +
'<option value=""></option>\n' +
'</select>\n' +
'\n' +
'</th>\n' +
'<td id="mm-transit">\n' +
'\n' +
'<div class="fake-input">\n' +
'<input value="" name="task_no[]" class="task_list" id="task_list_" type="text" title="Show category list here leter"><img class="show_task" id="show_task" src="<?=base_url()?>images/down.png">\n' +
'\t<div id="cat-list-" class="cat-list"><?php echo $categories_list ?></div>\n' +
'</div>\n' +
'</td>\n' +
el2 +
'\n' +
'<td style="text-align: center;">\n' +
'<input style="width: 35px;" id="text_total_'+ite+'" readonly=\'readonly\' class="short-textbox" type="text" name="total_'+ite+'" value="">\n' +
'</td>\n' +
'</tr>';
ite++;
$(el).appendTo($('#whc-table tbody'));
projectDropdown();
taskDropdown();
initializeMtree();
});
});
Note - same way i used to show mtree in normal rows means rows those are not generated by javascript that is
Try using
$('.btn-row-add').on('click', function() {
instead of
$('.btn-row-add').click(function() {
I have created list of items in a table. I want to calculate the price of checked items, but can't figure out how to update the data property when a checkbox is checked/unchecked. I have included the code for generating the list and updating the price calculation.
$.each(shopList, function (i, elem) {
var item = elem.item;
var link = elem.link;
var user = elem.user;
var price = elem.price;
var priority = elem.priority;
$(".listItems").append(
'<tr class="items" data-priority="' + priority + '">' +
'<td><input type="checkbox" class="priority"' + ((priority) ? 'checked' : '') + ' /></td>' +
'<td>' + '' + item + '' + '</td>' +
'<td>' + user + '</td>' +
'<td class="price">' + price + '</td>' +
'<td><button class="btn btn-default deleteItem">Del </button></td>' +
'</tr>'
);
});
And the code to update the price:
function updatePriority(){
sumPriority = 0;
$('tr.items[data-priority=true] .price').each(function () {
var total = $(this).text();
if (!isNaN(total) || total.length != 0) {
sumPriority += parseFloat(total);
};
});
$('.totalPriority').html(sumPriority.toFixed(2));
};
When the page renders it has checked and unchecked items and everything works that way at first, but not when a change is made.
How can I update the data-property true/false in the DOM?
Do not use data-property but just use the Checkbox :checked status
Instead of looping over the [data-priority=true] checkboxes you can loop over the checked checkboxes instead, and use parent().find('.price') to find the correct price labels.
function updatePriority(){
sumPriority = 0;
$('.priority:checked').each(function () {
var priceElement = $(this).parent().parent().find('.price');
var total = priceElement.text();
if (!isNaN(total) || total.length != 0) {
sumPriority += parseFloat(total);
};
});
$('.totalPriority').html(sumPriority.toFixed(2));
};
How can I update the data-property true/false in the DOM?
If you really want to keep your code as it is and only update the data-priority attribute when you change a checkbox you can implement change listeners on the checkboxes and change the parents attribute:
$('tr.items .price').change(function() {
if ($(this).is(":checked")) {
$(this).parent().parent().attr("data-priority",true);
}else{
$(this).parent().parent().attr("data-priority",false);
}
});
You can try this :
function updatePriority(){
sumPriority = 0;
$('.listItems tr td .priority').each(function () {
if ($(this).is(":checked"))
{
var price=$(this).parent().find('.price').text();
var total = price;
if (!isNaN(total) || total.length != 0) {
sumPriority += parseFloat(total);
};
}
});
$('.totalPriority').html(sumPriority.toFixed(2));
};
I've got a function that styles select inputs by generating a div with an anchor, list and a hidden field:
function selectMenu() {
var selectMenu = $("#cf-budget");
$('<input id="' + selectMenu.attr("id") + '-hidden" type="hidden" name="' + selectMenu.attr("name") + '" value="" />').insertAfter(selectMenu);
selectMenu.hide();
var selectTitle = selectMenu.children("option:eq(0)").text();
var newSelectMenu = '<div class="selectmenu"><div class="selectmenu-selected"><a rel="placeholder">'+ selectTitle +'</a></div><ul class="selectmenu-menu"><li><a rel="placeholder">'+ selectTitle +'</a></li>';
selectMenu.find("option:not(:eq(0))").each(function () {
newSelectMenu += '<li><a rel="' + $(this).val() + '">' + $(this).text() + "</a></li>";
});
newSelectMenu += "</ul></div>";
$(newSelectMenu).insertAfter(selectMenu);
var newSelectMenu = $("div.selectmenu");
$("div.selectmenu-selected a", newSelectMenu).live("click", function () {
$("ul.selectmenu-menu", newSelectMenu).toggle();
return false;
});
$("body").live("click", function () {
$("ul.selectmenu-menu", newSelectMenu).hide();
});
$("ul.selectmenu-menu a", newSelectMenu).live("click", function () {
var optionValue = $(this).attr("rel");
var optionText = $(this).text();
$("ul.selectmenu-menu", newSelectMenu).hide();
$("div.selectmenu-selected a", newSelectMenu).text(optionText);
$("#" + selectMenu.attr("id") + "-hidden").val(optionValue);
var activeMessageType = $("ul.message-type.active");
if (activeMessageType.length) {
activeMessageType.slideUp(300, function () {
$("#" + optionValue).addClass("active").slideDown(300);
}).removeClass("active");
} else {
$("#" + optionValue).addClass("active").slideDown(300);
}
return false;
});
}
$(document).ready(function() {
selectMenu();
});
My question is how can I adjust this to make it work for 'x' amount of select inputs? Currently it only takes the Id or class of a single select.
I'm guessing I'd need to pass the function a select id or class name so that it can do it stuff to each dropdown?
I have made a jsFiddle here for this that now is fully working: http://jsfiddle.net/7TaqN/1/
The suggestion by ach was perfect, however there was an issue with the body of your code. The following changes had to be made to make it work:
This line had to be removed as it overrode the 'this' selector:
var selectMenu = $("#cf-budget");
This line had to be modified to select the class with the ID of the element clicked to
prevent all elements from being affected:
$(newSelectMenu).insertAfter(selectMenu);
var newSelectMenu = $("div.selectmenu#"+ selectMenu.attr("id"));
This is the full working code as a jQuery module:
(Note this will only work with jQuery 1.8 as the .live() method you are using is deprecated in 1.9
$.fn.selectMenu = function () {
return this.each(function () {
var selectMenu = $(this);
//Body of your selectMenu() function goes here
//All selectors should be in the context of the selectMenu element
$('<input id="' + selectMenu.attr("id") + '-hidden" type="hidden" name="' + selectMenu.attr("name") + '" value="" />').insertAfter(selectMenu);
selectMenu.hide();
var selectTitle = selectMenu.children("option:eq(0)").text();
var newSelectMenu = '<div id="' + selectMenu.attr("id") + '" class="selectmenu"><div id="' + selectMenu.attr("id") + '" class="selectmenu-selected"><a rel="placeholder">' + selectTitle + '</a></div><ul class="selectmenu-menu"><li><a rel="placeholder">' + selectTitle + '</a></li>';
selectMenu.find("option:not(:eq(0))").each(function () {
newSelectMenu += '<li><a rel="' + $(this).val() + '">' + $(this).text() + "</a></li>";
});
newSelectMenu += "</ul></div>";
$(newSelectMenu).insertAfter(selectMenu);
var newSelectMenu = $("div.selectmenu#"+ selectMenu.attr("id"));
$("div.selectmenu-selected a", newSelectMenu).live("click", function () {
$("ul.selectmenu-menu", newSelectMenu).toggle();
return false;
});
$("body").live("click", function () {
$("ul.selectmenu-menu", newSelectMenu).hide();
});
$("ul.selectmenu-menu a", newSelectMenu).live("click", function () {
var optionValue = $(this).attr("rel");
var optionText = $(this).text();
$("ul.selectmenu-menu", newSelectMenu).hide();
$("div.selectmenu-selected a", newSelectMenu).text(optionText);
$("#" + selectMenu.attr("id") + "-hidden").val(optionValue);
var activeMessageType = $("ul.message-type.active");
if (activeMessageType.length) {
activeMessageType.slideUp(300, function () {
$("#" + optionValue).addClass("active").slideDown(300);
}).removeClass("active");
} else {
$("#" + optionValue).addClass("active").slideDown(300);
}
return false;
});
});
};
$(document).ready(function () {
$('.mySelectClass').selectMenu();
});
You could make it into a jQuery plugin:
$.fn.selectMenu = function() {
return this.each(function() {
var selectMenu = $(this);
//Body of your selectMenu() function goes here
//All selectors should be in the context of the selectMenu element
});
};
Then use it with standard jQuery selectors like so:
$('.mySelectClass').selectMenu();
Edit: Looks like you're already setting the context using the second parameter of jQuery() so additional use of find shouldn't be necessary. That's a lot of code to parse through visually, though -- a jsfiddle might help.
You'll also need to replace some of your selectors so that they're evaluated on the children of the selectMenu element, for example:
selectMenu.find("div.selectmenu-selected a", newSelectMenu).live("click", function () {
I have some code which adds fields but currently it adds an infinite abouts of boxes. How can I constrain it to only be a max of 10. I ideally want it to alert when I try to add more after 10.
http://jsfiddle.net/spadez/9sX6X/13/
var container = $('.copies'),
value_src = $('#current');
$('.copy_form')
.on('click', '.add', function(){
var value = value_src.val();
var html = '<div class="line">' +
'<input class="accepted" type="text" value="' + value + '" />' +
'<input type="button" value="X" class="remove" />' +
'</div>';
$(html).appendTo(container);
value_src.val('');
})
.on('click', '.remove', function(){
$(this).parents('.line').remove();
});
The code I know:
alert("Only 10 allowed");
The code I had a go at:
var i = 0 // Set counter
i++ // Increment counter
if(i > 10) {
alert("Only 10 allowed");
}
else {
// code to be executed
}
This is one of my first scripts and I wondered if I could get help on the right way to implement this because the code I tried above broke my current working code.
Within your click handler, check if the number of elements with the class line is less than 10.
if ($('.line').length < 10) {
//execute code
}else{
alert('Only 10 allowed');
return false;
}
Fiddle
Rather than embedding 'magic numbers' in your code (see: What is a magic number, and why is it bad?), define a maxFields variable and maintain a count throughout, checking against that value each time another one tries to be added.
This allows your code to be more portable and reusable by someone else, or by you for another use case, when say you want 20 fields.
It also reads more like English (current field is less than max fields) which leads to self documentation.
http://jsfiddle.net/9sX6X/21/
var container = $('.copies'),
value_src = $('#current'),
maxFields = 10,
currentFields = 1;
$('.copy_form').on('click', '.add', function () {
if (currentFields < maxFields) {
var value = value_src.val();
var html = '<div class="line">' +
'<input class="accepted" type="text" value="' + value + '" />' +
'<input type="button" value="X" class="remove" />' +
'</div>';
$(html).appendTo(container);
value_src.val('');
currentFields++;
} else {
alert("You tried to add a field when there are already " + maxFields);
}
})
.on('click', '.remove', function () {
$(this).parents('.line').remove();
currentFields--;
});
From Wikipedia:
The term magic number also refers to the bad programming practice of
using numbers directly in source code without explanation. In most
cases this makes programs harder to read, understand, and maintain.
Although most guides make an exception for the numbers zero and one,
it is a good idea to define all other numbers in code as named
constants.
Here I used the .length method from jQuery.
var container = $('.copies'),
value_src = $('#current');
$('.copy_form')
.on('click', '.add', function(){
if ($('.accepted').length < 10)
{
var value = value_src.val();
var html = '<div class="line">' +
'<input class="accepted" type="text" value="' + value + '" />' +
'<input type="button" value="X" class="remove" />' +
'</div>';
$(html).appendTo(container);
value_src.val('');
}
else
{
alert("Only 10 allowed");
}
})
.on('click', '.remove', function(){
$(this).parents('.line').remove();
});
Fiddle
I'm trying to get the values of some input tags for doing some validation before continuing. My form is located inside of a jQuery Dialog box of which the HTML is dynamically generated based on the number of elements within a JSON array like so -
if (testDialog === null)
{
myTestDialogContentDiv += '<div id="TestDialog" style="padding-left: 0; top: 0px; left: 0px;">';
}
myTestDialogContentDiv += '<div id="TestDialogWarning" class="ClockInner"></div>';
myTestDialogContentDiv += '<div id="TestDialogText" class="ClockInner" style="position: relative;"></div>';
myTestDialogContentDiv += '<div class="TestDialogTxt"></div>';
myTestDialogContentDiv += '<form>'; //Start Form
myTestDialogContentDiv += '<p><b>Routing Out:</b></p>';
if (data.routesout.length > 1)
{
for(i=0;i<data.routesout.length;i++)
{
myTestDialogContentDiv += '<label for="route' + i + '">' + data.routesout[i].name + '(%)</label>';
myTestDialogContentDiv += '<input onkeypress="validateKeypress(event)" type="text" name="route' + i + '" id="route' + i + '" value="' + data.routesout[i].percent + '" maxlength="5" size="8" class="ui-widget-content ui-corner-all">';
myTestDialogContentDiv += '</br>'
}
}
else
{
myTestDialogContentDiv += '<label>' + data.routesout[0].name + '(%)</label>';
myTestDialogContentDiv += '<input type="text" name="route0" id="route0" disabled value="' + data.routesout[0].percent + '" maxlength="5" size="8" "class="ui-widget-content ui-corner-all">';
}
And this is my code for creating a Dialog box with the form data embedded in it, along with my "on submit" validation.
TestDialog = $("#TestDialog");
TestDialog.dialog({
title: data.name,
resizable: true,
closeOnEscape: true,
zIndex: 1000,
dialogClass: 'outerGlow hideCloseX testDialog',
buttons: {
"Save":function() {
//Need to check that all the fields add up to EXACTLY 100%
var total = 0;
for(var i=0; i< data.routesout.length; i++)
{
total += ("#route" + i).val();
}
if (total !== 100)
{
alert("NOT EQUAL TO 100!!!");
}
else
{
//TODO - Add Requests to update objects
$(this).dialog("close");
}
},
"Cancel": function() { $(this).dialog("close"); }
}
});
I'm getting a Jscript error saying that .val doesn't exist for that element, when I try to use Jscripts own .value I get a NaN. I think it's something to do with the form technically being a child node? But nonetheless I'm stumped, any help would be great.
Also ignore any spelling mistakes or inconsistencies in my spellings of ids etc, I quickly changed it to Test for posting.
Thanks!
total += ("#route" + i).val(); should be total += parseInt($("#route" + i).val());