how to serialize a form under specific conditions - javascript

Taka a look at this fiddle here this is a form where a business user enters the offered services.I sent the data with ajax and by serializing the form.
Click edit and add(plus sign) a service...in the example an input is added where it's name attribute value is of this **form= form[5]...**contrast with this with the form of the name attribute value in the other inputs...only the newly added services have the name attribute like this and the reason for that is to serialize only these...and not the others already present in the DOM/stored in the DB.
And now my problem:
Imagine that the user goes to edit the already registered services(or that he goes to edit them and add a new one)...at this case the already registered services wont'be serialized cause of the form the name attribute value has...(and the reason for this is explained above).
What can I do in this case?Sometimes I must serialize only part of a form and sometimes whole of the form.If all the inputs have name attribute value of form[1....] then along with the newly added input...already registered services will be serialized again.
Thanks for listening.
Code follows(you can see it in the fiddle too)
$('.editservices').click(function() {
//console.log(('.wrapper_servp').length);
originals_ser_input_lgth = $('.services').length;
var originals = [];
$('.show_price')
// fetch only those sections that have a sub-element with the .value
class
.filter((i, e) => $('.value', e).length === 1)
// replace content in remaining elements
.replaceWith(function(i) {
var value = $('.value', this).data('value');
var fieldsetCount = $('#serv').length;
var index = fieldsetCount + i;
return '<div class="show_price"><p id="show_p_msg">Price
visibility</p></div>' + '\
<div class="show_p_inpts">' +
'<input class="price_show"' + (value == 1 ? "checked" : "") + '
type="radio" name="form[' + index + '][price_show]" value="1">yes' +
'<input class="price_show"' + (value == 0 ? "checked" : "") + '
type="radio" name="form[' + index + '][price_show]" value="0">no' +
'</div>'; // HTML to replace the original content with
});
$('#buttons').removeClass('prfbuttons');
$('#saveserv').addClass('hideb');
$('.actionsserv').removeClass('actionsserv');
priceavail = $(".price_show:input").serializeArray();
});
$('#addser').on('click', function() {
$('#saveserv').css('border','2px solid none');
var serviceCount = $('input.services').length + 1;
var serv_inputs = '<div class="wrapper_servp"><div class="serv_contain">\n\
<input placeholder="service" class="services text" name="form[' + serviceCount + '][service]" type="text" size="40"> \n\
<input placeholder="price" class="price text" name="form[' + serviceCount + '][price]" type="text" size="3"></div>';
var p_show = '<div class="show_p">' +
'<p id="show_p_msg">Price visibility;</p>' +
'<span id="err_show_p"></span><br>' +
'</div>';
var inputs = '<div class="show_p_inpts">' +
'<input class="price_show" type="radio" name="form[' + serviceCount + '][price_show]" value="1">yes' +
'<input class="price_show" type="radio" name="form[' + serviceCount + '][price_show]" value="0">no' +
'</div></div>';
$('.wrapper_servp').last().after(serv_inputs + p_show + inputs);
$('#saveserv').removeClass('hideb');
$('#remser').css('display', 'inline');
});
$('#cancelserv').click(function(e) {
e.preventDefault();
//var newinputs = $('.wrapper_servp').length;
//var inp_remv = newinputs - originals_ser_input_lgth;
//$('.wrapper_servp').slice(-inp_remv).remove()
$('.show_p_inpts')
.filter((i, e) => $('.price_show:checked', e).length === 1)
.replaceWith(function(i) {
var value = $('.price_show:checked').attr('value');
return '<span data-value="' + value + '" class="value">' + (value == 1 ? "yes" : "no") + '</span>'
});
});
var groupHasCheckedBox = function() {
return $(this).find('input').filter(function() {
return $(this).prop('checked');
}).length === 0;
},
inputHasValue = function(index) {
return $(this).val() === '';
};
$('#saveserv').click(function(e) {
e.preventDefault();
//from here
var $radioGroups = $('.show_p_inpts');
$('.show_p_inpts').filter(groupHasCheckedBox).closest('div').addClass("error");
$('.services, .price').filter(inputHasValue).addClass("error");
//to here
var $errorInputs = $('input.services').filter((i, e) => !e.value.trim());
if ($errorInputs.length >= 1) {
console.log($errorInputs);
$('#err_message').html('you have to fill in the service'); return;
}
if ($('input.price').filter((i, e) => !e.value.trim()).length >= 1) {
$('#err_message').html('you have to fill in the price'); return;
}
});
var IDs=new Array();
$('body').on('click', '#remser', function(e){
var inputval=$('.services:visible:last').val();
if(inputval!=='')
{r= confirm('Are you sure you want to delete this service?');}
else
{
$('.wrapper_servp:visible:last').remove();
}
switch(r)
{
case true:
IDs.push($('.services:visible:last').data('service'));
$('.wrapper_servp:visible:last').addClass('btypehide');
if($('.serv_contain').length==1)$('#remser').css('display','none');
$('#saveserv').removeClass('hideb').css('border','5px solid red');
//originals.servrem=true;
break;
case false:var i;
for(i=0;i<originals.ser_input_lgth;i++)
{
$('input[name="service'+i+'"]').val(services[i].value);
$('input[name="price'+i+'"]').val(prices[i].value);//εδω set value
}
$('.services').slice(originals.ser_input_lgth).remove();
$('.price').slice(originals.ser_input_lgth).remove();
$('.openservices').addClass('hide').find('.services,.price').prop('readonly', true);
var text='<p class="show_price">Θες να φαίνεται η τιμή;<span data-value="'+ show_pr_val.value +'" class="value">' +(show_pr_val.value==1 ? 'yes':'no') + '</span></p>';
$('.show_p_inpts').remove();
$('.show_price').replaceWith(text);;
break;
}
});

I have an Idea for you. What you can do is when you show the currently existed value in you html instead of giving name attribute just give data-name attribute. I.e
Change this
<input class="services text" data-service="21" size="40" value="hair" type="text" name="service0" readonly="">
To This
<input class="services text" data-service="21" size="40" value="hair" type="text" data-value="hair" data-name="service0" readonly="">
Now when user update this values you can bind an event in jQuery like below.
$(document).ready(function(){
$(".services input").on("change paste keyup", function() {
if($(this).val() === $(this).attr("data-value"))
{
$(this).removeAttr("name");
}else{
$(this).attr("name",$(this).attr("data-name"));
}
});
});
By this way you can give name attribute to only those elements whose values are changed. Now each time you can serialize the whole form and it will only get the value of changed elements.
Don't forget to give unique class to already existed elements so you can bind on change event. Hope its clear to you.

Related

using .on to listen for event not working

I am trying to use .on to listen for an event.
html:
<div class="form-group" id="group_names">
<label> Names: </label><br>
<input type="text" class="form-control name" placeholder="name1" id="name1" name ="name1"><br>
</div>
JS:
for (n = 1; n < inputLength+3 ; ++n) {
var test2 = document.getElementById(dude+n);
$(test2).on('change', '#group_names', forFunction);
}
The change to the input field is not being recognized.
Additionally, I am hoping .on will recognize changes made to new html i am injecting using the following function:
var dude = "name";
function forFunction() {
for (m = 1; m < inputLength + 1; ++m) {
var test = document.getElementById(dude + m)
if (test.value != "") {
var txt = "<input type=\"text\" class=\"form-control name\" placeholder=" + dude + (m + 1) + " id=" + dude + (m + 1) + " name=" + dude + (m + 1) + "><br>";
document.getElementById('group_names').insertAdjacentHTML('beforeend', txt);
//function updateHTML(txt)
}
}
}
I am not sure if my syntax for .on is correct. I am trying to use "#group_names" as the selector, but not sure if I am doing it right.
Thanks
You probably want to use event delegation on the parent div instead.
$('#group_names').on('change', 'input.form-control.name', forFunction);
Consider the following jQuery code.
$(function() {
var inputFields = $("input[id*='name']");
function forFunction(evt) {
console.log(evt.type);
inputFields.each(function(i, el) {
var n = i + 1;
if ($(el).val() != "") {
console.log("Value Detected");
$("<input>", {
type: "text",
class: "form-control name",
placeholder: "group" + n,
id: "group" + n,
name: "group" + n
}).insertBefore("#group_names");
}
});
}
inputFields.on("change", forFunction);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="form-group" id="group_names">
<label> Names: </label><br>
<input type="text" class="form-control name" placeholder="name1" id="name1" name="name1"><br>
</div>
This should work for all of the Input items.

Iterating Ajax response and creating Dynamic table on some condition

I am trying to create a dynamic table with ajax response.
And want to put condition on check box like if item.statuscheck =1 will print checked Box with name and if item.statuscheck =0 unchecked box will display with same name.
i am able to display name dynamically. But problem is coming with check box.
Here is the code i am trying with. Please help me on this issue.
success(response)
{
$.each(response,function(index,item){
var status;
if(index >=0 and index <= 4)
{
if(item.statusCheck = 1)
{
status = <input type ="checked" checked/>
}
else{
status = <input type="checked" />
}
var content = '<td>'+ status + '</td>'
+<td>' + item.fieldName +'<td>';
$("#tableId").appent(content)
}
}
}
("#tableId").append(content)
Change appent to append
compare operator is == not = assign.Also careful 'and "
success(response)
{
$.each(response,function(index,item){
var status;
if(0 >= index <= 4)
{
if(item.statusCheck == 1)
{
status = '<input type ="checkbox" checked/>';
}
else{
status = '<input type="checkbox" />';
}
var content = '<td>'+ status + '</td>'
+'<td>' + item.fieldName +'<td>';
$("#tableId").append(content);
}
}
}
var content = item.statusCheck == 1 ? '<td><input type="checkbox" checked="checked" />'+item.fieldName+'</td>' : '<td><input type="checkbox" />'+item.fieldName+'</td>';
$("#tableId").append($(content));
Its not type = "checked" its type = "checkbox"
success(response)
{
$.each(response,function(index,item){
var status;
if(index >=0 and index <= 4)
{
if(item.statusCheck = 1)
{
status = <input type ="checkbox" checked/>
}
else{
status = <input type="checkbox"/>
}
var content = '<td>'+ status + '</td>'
+<td>' + item.fieldName +'<td>';
$("#tableId").appent(content)
}
}
}

How to add or delete fields depending on value of another field

I have form:
<div class="fieldWrapper">
<label for="id_rooms">Rooms:</label>
<input id="id_rooms" type="number" name="rooms" min="1">
</div>
<div class="extrafieldWrapper">
</div>
Depending on number of rooms i want to add or delete new fields "adult" and "children". For example: if value of field "room" will be 2, it should generate two couples another fields for each room 'adult' and 'children', but if change value from 2 on 1, it should delete one couple of fields. And when change the value of 'room' field from 2 to 3, it should add one couple of fields. I saw many examples how to do this on java-script, so i try to write the script by my self, but it doesn't work correctly. Depending on value of field 'room' it only add new couple of fields.
$(function() {
var newFields = $('');
$('#id_rooms').bind('blur keyup change', function() {
var n = this.value || 0;
if (n + 1) {
if (n > newFields.length) {
addFields(n);
} else {
removeFields(n);
}
}
});
function addFields(n) {
for (form_num = newFields.length; form_num < n; form_num++) {
$("input[id='id_form-TOTAL_FORMS']").attr('value', form_num + 1);
$(".extrafieldWrapper").append("<br/><label for='id_form-" + form_num + "-adult'>Adult:</label> <input id='id_form-" + form_num + "-adult' type='number' name='form-" + form_num + "-adult'/> <label for='id_form-" + form_num + "-children'>Children:</label> <input id='id_form-" + form_num + "-children' type='number' name='form-" + form_num + "-children'/> ");
}
}
function removeFields(n) {
$('.extrafieldWrapper').html('');
}
});
I am newbie in java-script, can you tell me what i'm doing wrong. Thanks a lot.
It's a bit unclear what behavior exactly you wanted. Here I tried to represent it with code:
$(function () {
$('#id_rooms').bind('blur keyup change', function () {
var n = $('#id_rooms').val() || 0;
$("input#id_form-TOTAL_FORMS]").attr('value', n);
$(".extrafieldWrapper").empty();
for (var i = 0; i < n; i++) {
$(".extrafieldWrapper").append("<br/><label for='id_form-" + i + "-adult'>Adult:</label> <input id='id_form-" + i + "-adult' type='number' name='form-" + i + "-adult'/> <label for='id_form-" + i + "-children'>Children:</label> <input id='id_form-" + i + "-children' type='number' name='form-" + i + "-children'/>");
}
});
});
Anyway, you don't need two functions for adding and removing fields. You only need to rewrite the whole content of your div in one cycle. Or, if you prefer two functions approach, then you need to gather all the tags describing one pair of fields you add/remove under one div or span and give each of such groups an unique id by which you would address it.

Build a array of div's id using each DIV inside section

I'm trying to get the ID of each DIV inside this HTML code
<section id="choices">
<div id="talla_choice_24" style="">
...
</div>
<div id="color_choice_25" style="">
...
</div>
<div id="sport_choice_26" style="">
...
</div>
<button type="button" class="create-variation" id="create-variation" style="">Crear variaciones</button>
<section id="variations_holder" style="display: none"></section>
</section>
So I made this:
function getDivId(div) {
var inputValues = [];
$("#" + div + ' > div').each(function() {
inputValues.push($(this).val());
})
return inputValues;
}
And I call here:
$('#choices').on("click", "#create-variation", function(e) {
var parent_id = $(this).closest("section").attr("id");
var element = getDivId(parent_id);
iterateChoices("", element[0], element.slice(1), 0);
});
I need to build something like this:
var element = new Array($('#talla_choice_24 input:text'), $('#color_choice_25 input:text'), $('#sport_choice_26 input:text'));
But I get this error:
Uncaught TypeError: Object has no method 'each'
What is wrong?
UPDATE
This is the code for iterateChoices() function:
function iterateChoices(row, element, choices, counter) {
if ($.isArray(choices) && choices.length > 0) {
element.each(function(index, item) {
if (counter == 0)
row = '<input type="text" required="required" value="" name="pupc[]" /><input type="text" required="required" value="" name="pprice[]" /><input type="text" required="required" value="" name="pqty[]" />';
iterateChoices(row + '<input value="' + item.value + '">', choices[0], choices.slice(1), counter + 1);
});
} else {
html_temp = "";
$.each(element, function(index, item) {
html_temp += row + '<input value="' + item.value + '"><br>';
});
html += html_temp;
}
}
I also made some changes at this code:
function getDivId(div) {
var inputValues = [];
$("#" + div + ' > div').each(function() {
inputValues.push("#" + $(this).attr('id') + ' input:text');
});
return inputValues;
}
And now the error change to this:
Uncaught TypeError: Object #talla_choice_24 input:text has no method 'each'
UPDATE 2
I still continue change getDivId() function to build a array like this:
var element = new Array($('#talla_choice_24 input:text'), $('#color_choice_25 input:text'), $('#number_choice_23 input:text'), $('#sport_choice_23 input:text'));
But can't get it since array values are constructed as strings, see below:
function getDivId(div) {
var inputValues = [];
$("#" + div + ' > div').each(function() {
inputValues.push('$("#' + $(this).attr('id') + ' input:text")');
});
return inputValues;
}
I'm getting:
("$('#talla_choice_24 input:text')", "$('#color_choice_25 input:text')")
I think there is the problem
You are using the val method on a div element, which just returns an empty string. There is no each method on a string.
You don't need the id of each div to get the input elements inside them. This will get you the inputs in a single jQuery object:
var element = $(this).closest("section").find("> div input:text");
If you really need an array of separate jQuery objects, you can then do this:
element = element.map(function(){ return $(this); }).get();
var arr = [];
$("#create-variation").on('click', function(){
$("#choices > div").each(function(a,b){
arr.push($(this).text());
});
});
After some headaches I realized how to fix the (my) error, here is the solution to all the problems:
function getDivId(div) {
var inputValues = [];
$("#" + div + ' > div').each(function() {
inputValues.push($("#" + $(this).attr('id') + " input:text"));
});
return inputValues;
}

JavaScript For Loop Round Form Input Fields

I'm currently working on creating an expenses form and am writing a function to validate the entered data.
I allow for 6 expense amounts to be entered and a description on each and onClick of the submit button I am trying to write a for loop that will loop round the amount fields, check if they are numeric and, if they are, then check to ensure a description has been entered.
The form basically looks like:
<form action="##" name="myForm" id="myForm" method="post">
<input type="text" name="otherExpenseDesc1" id="otherExpenseDesc1">
<input type="text" name="otherExpenseAmount1" id="otherExpenseAmount1">
<input type="text" name="otherExpenseDesc2" id="otherExpenseDesc2">
<input type="text" name="otherExpenseAmount2" id="otherExpenseAmount2">
<input type="text" name="otherExpenseDesc3" id="otherExpenseDesc3">
<input type="text" name="otherExpenseAmount3" id="otherExpenseAmount3">
<input type="text" name="otherExpenseDesc4" id="otherExpenseDesc4">
<input type="text" name="otherExpenseAmount4" id="otherExpenseAmount4">
<input type="text" name="otherExpenseDesc5" id="otherExpenseDesc5">
<input type="text" name="otherExpenseAmount5" id="otherExpenseAmount5">
<input type="text" name="otherExpenseDesc6" id="otherExpenseDesc6">
<input type="text" name="otherExpenseAmount6" id="otherExpenseAmount6">
<input type="submit" name="formSubmitBtn" value="SUBMIT" onClick="checkForm();">
</form>
And the javascript I have at the moment is:
function checkForm() {
var errMsg = "";
var otherExpense1 = document.getElementById('otherExpenseAmount1').value;
var otherExpenseDesc1 = document.getElementById('otherExpenseDesc1').value;
var otherExpense2 = document.getElementById('otherExpenseAmount2').value;
var otherExpenseDesc2 = document.getElementById('otherExpenseDesc2').value;
var otherExpense3 = document.getElementById('otherExpenseAmount3').value;
var otherExpenseDesc3 = document.getElementById('otherExpenseDesc3').value;
var otherExpense4 = document.getElementById('otherExpenseAmount4').value;
var otherExpenseDesc4 = document.getElementById('otherExpenseDesc4').value;
var otherExpense5 = document.getElementById('otherExpenseAmount5').value;
var otherExpenseDesc5 = document.getElementById('otherExpenseDesc5').value;
var otherExpense6 = document.getElementById('otherExpenseAmount6').value;
var otherExpenseDesc6 = document.getElementById('otherExpenseDesc6').value;
for (i=1; i<7; i++) {
expenseNo = 'otherExpense' + i;
expenseDescNo = 'otherExpenseDesc' + i;
if (expenseNo != "") {
if (isNaN(expenseNo)) {
alert(expenseNo + ' is not a number');
errMsg = errMsg + 'The amount must be a number.<br />';
document.getElementById('otherExpenseAmount' + i).style.border = '2px sold #990000';
} else {
alert('otherExpenseAmount' + i + ' is a number');
document.getElementById('otherExpenseAmount' + i).style.border = '2px sold #990000';
}
}
}
if (errMsg != "") {
showDialog('alert', 'OK', '', errMsg, '');
}
}
When I'm submitting the form with valuesin a couple of the fields it still displays an alert for each otherExpenseAmount item saying that it is not numeric, although it is, and the border style doesn't change.
Any idea where I'm going wrong?
You're trying to access a variable with a string. You should change your code to utilise arrays, something like this:
jsFiddle
function checkForm() {
var errMsg = "";
var otherExpense = [];
otherExpense.push(document.getElementById('otherExpenseAmount1').value);
otherExpense.push(document.getElementById('otherExpenseAmount2').value);
otherExpense.push(document.getElementById('otherExpenseAmount3').value);
otherExpense.push(document.getElementById('otherExpenseAmount4').value);
otherExpense.push(document.getElementById('otherExpenseAmount5').value);
otherExpense.push(document.getElementById('otherExpenseAmount6').value);
// 0-based index for arrays
for (i=0; i<6; i++) {
if (otherExpense[i] != "") {
if (isNaN(otherExpense[i])) {
alert('otherExpense ' + (i + 1) + ' is not a number (=' + otherExpense[i] + ')');
errMsg = errMsg + 'The amount must be a number.<br />';
document.getElementById('otherExpenseAmount' + (i + 1)).style.border = '2px sold #990000';
} else {
alert('otherExpenseAmount' + (i + 1) + ' is a number');
document.getElementById('otherExpenseAmount' + (i + 1)).style.border = '2px sold #990000';
}
}
}
if (errMsg != "") {
alert(errMsg);
//showDialog('alert', 'OK', '', errMsg, '');
}
return false;
}
Your problem is on these lines; you're setting the border to be the same, regardless of the condition (easy mistake to make).
if (isNaN(expenseNo)) {
alert(expenseNo + ' is not a number');
errMsg = errMsg + 'The amount must be a number.<br />';
document.getElementById('otherExpenseAmount' + i).style.border = '2px sold #990000';
// -----------------------------------------------------------------------------^^^^^^
} else {
alert('otherExpenseAmount' + i + ' is a number');
document.getElementById('otherExpenseAmount' + i).style.border = '2px sold #990000';
// -----------------------------------------------------------------------------^^^^^^
}
Suggestion
I hate to be that guy.
Have you considered adopting jQuery? It's perfectly designed for tasks such as this.
Utilising methods such as filter and simple selectors, it's easy to determine whether all inputs fulfil your requirements. Here's an example:
// select all inputs with a class of "number"
// then filter those inputs, selecting only those where the value is "not a number"
// if there is a length, i.e. more than 0 were found, alert a message
if ($('input.number').filter(function() { return isNaN(this.value); }).length) {
alert('Please ensure all numbers are valid');
}
This would obviously require you to make small amendments to your HTML, by adding the number class to the required elements, but it's a small sacrifice to make.
jsFiddle demo

Categories

Resources