Make hidden div and inputs optional for valid form submit with jquery.validate - javascript

I have a form that may only be one page or may be two pages depending on whether it is a single individual or two people applying. What I am doing right now is enabling a link that allows the user to get to the next group of form elements for their co-applicant via an onchange event that shows the link that will slideToggle the first users inputs and show the inputs for the additional users. It's a pretty lengthy form so I cut it down to a few elements so I could fiddle it out:
Das Fiddle is here
<form method="POST" id="refiLoanForm" action="mailto:i#i.com">
<!--START PRIMARY APPLICANT -->
<div id="primary-applicant">
<label>
Application Type
<select name="applicationType" id="applicationType" class="wider" required>
<option value="individual">Individual</option>
<option value="joint">Joint</option>
</select>
</label>
<br>
<label for="loan-amount" id="loan-amount-label">Requested Finance Amount
<input type="text" id="loan-amount" name="loanAmount" required/></label>
<br>
<label for="remaining-term">Current Loan Remaining Term
<input type="text" id="remaining-term" name="remainingTerm" max="3" size="3" required class="override"/>
</label>
<br>
CONTINUE TO CO-APPLICANT
</div>
<!--END PRIMARY APPLICANT -->
<!--START CO_APPLICANT -->
<div id="co-applicant" style="display: none">
Back to Primary Applicant
<br>
<label for="co-first-name">First Name
<input type="text" id="co-first-name" name="coApplicantGivenName" maxlength="32" required/>
</label>
<br>
<label for="co-last-name">Last Name
<input type="text" id="co-last-name" name="coApplicantFamilyName" maxlength="32" required/>
</label>
</div>
JS:
$('#refiLoanForm').validate({
onkeyup: false,
ignore: ":disabled",
submitHandler: function (form) { // for demo
alert('valid form');
return false;
}
});
$("#singleSubmitBtnLoan").bind('click', function () {
$('#refiLoanForm').valid();
});
//Handle the content being shown
$("#singleSubmitBtnLink2").on('click', function () {
$("#primary-applicant").slideToggle("slow");
$("#co-applicant").slideToggle("slow");
});
$("#backToPrimary").on('click', function () {
$("#primary-applicant").slideToggle("slow");
$("#co-applicant").slideToggle("slow");
});
$('#applicationType').on('change', function() {
if ($(this).val() === 'joint') {
$('.primaryApplicantSwitch').slideToggle("slow");
$('.jointApplicantSwitch').slideToggle("slow");
} else {
$('.primaryApplicantSwitch').slideToggle("slow");
$('.jointApplicantSwitch').slideToggle("slow");
}
});
So in theory, the user can enter the fields and hit submit and the form is either valid or throws some errors. Or, the user can add a co-applicant, and validate the form on the link click before toggling to the next group of inputs.
Any ideas on how I would bind all of this to the one button and get it to play nice with jquery.validate?

You cannot dynamically "toggle" the rules of input fields.
However, you can use the .rules() method to dynamically add/change/remove rules, which essentially mimics the behavior of a toggle.
Also, since you're talking about fields that are hidden, you'll need to disable the option that makes validation ignore all hidden fields.
ignore: []

Related

Adding input elements to the DOM using jQuery

I am programming a web application which accepts barcodes from a barcode reader in an input field. The user can enter as many barcodes that s/he wants to (i.e. there is no reason for a predefined limit). I have come up with a brute force method which creates a predefined number of hidden input fields and then reveals the next one in sequence as each barcode is entered. Here is the code to do this:
<form id="barcode1" name="barcode" method="Post" action="#">
<div class="container">
<label for="S1">Barcode 1 &nbsp </label>
<input id="S1" class="bcode" type="text" name="S1" onchange="packFunction()" autofocus/>
<label for="S2" hidden = "hidden">Barcode 2 &nbsp </label>
<input id="S2" class="bcode" type="text" hidden = "hidden" name="S2" onchange="packFunction()" />
<label for="S3" hidden = "hidden">Barcode 3 &nbsp </label>
<input id="S3" class="bcode" type="text" hidden = "hidden" name="S3" onchange="packFunction()" />
<label for="S4" hidden = "hidden">Barcode 4 &nbsp </label>
<input id="S4" class="bcode" type="text" hidden = "hidden" name="S4" onchange="packFunction()" />
<label for="S5" hidden = "hidden">Barcode 5 &nbsp </label>
<input id="S5" class="bcode" type="text" hidden = "hidden" name="S5" onchange="packFunction()" />
</div>
<div class="submit">
<p><input type="submit" name="Submit" value="Submit"></p>
</div>
</form>
<script>
$(function() {
$('#barcode1').find('.bcode').keypress(function(e){
// to prevent 'enter' from submitting the form
if ( e.which == 13 )
{
$(this).next('label').removeAttr('hidden')
$(this).next('label').next('.bcode').removeAttr('hidden').focus();
return false;
}
});
});
</script>
This seems to be an inelegant solution. It would seem to be better to create a new input field after each barcode has been entered. I have tried creating new input elements in the DOM using jQuery, and I can get the new input element to show. But it uses the onchange event, which detects changes in the original input field. How do I transfer focus and detect onchange in the newly created input field? Here is the code that I have played with to test out the idea:
<div>
<input type="text" id="barcode" class="original"/>
</div>
<div id="display">
<div>Placeholder text</div>
</div>
<script src="./Scripts/jquery-2.2.0.min.js"></script>
$(function () {
$('#barcode').on('change', function () {
$('#display').append('<input id='bcode' class='bcode' type='text' name='S1' autofocus/>')
});
});
</script>
Once I have these barcodes, I pack them into array which I then post them to a server-side script to run a mySQL query to retrieve data based on the barcodes, and then post that back to the client. So part of what I have to achieve is that each barcode that is entered into the different input fields need to be pushed into an array.
Is there an elegant way to accomplish the creation of input fields dynamically and then detecting changes in those to create yet more input fields?
The dynamic update you have tried out is all right. If you must push it into an array on submit you have to prevent default of form submit, serialize the form and then make an ajax request.
Heres an example:
$('form').on('submit',function(e){
e.preventDefault();
var formData = $(this).serializeArray();//check documentation https://api.jquery.com/serializeArray/ for more details
$.ajax({
type:'post',
url:<your url>//or you could do $('form').attr('action')
data:formData,
success:function(){}//etc
})
});
If you do not display the barcodes in the html you can skip the input fields and store the read barcodes in an array[]. Not everything that happens in javascript has to be displayed in the website (View) . i do not know what code you use to scan the barcode but you do not need the input-elements at all.
See the example on this site https://coderwall.com/p/s0i_xg/using-barcode-scanner-with-jquery
instead of console.log() the data from the barcode scanner can simply be saved in an array[] and be send from there.
If you want to create elements dynamcially see this thread: dynamically create element using jquery
The following code adds the p-element with the label "Hej" to the div "#contentl1"
`$("<p />", { text: "Hej" }).appendTo("#contentl1");`
UPDATE: I added some simple CSS to make each input field display on its own line.
Here's one strategy:
Listen for the enter/return key on the input box.
When the enter/return key is pressed (presumably after entering a barcode), create a new input box.
Stop listening for the enter key on the original input and start listening for it on the new input.
When a "submit all" button is pressed (or when tab is used to shift the focus from the most recent input to the "submit all" button and enter is pressed), then collect all the input values in an array.
$(function() {
var finishBarcode = function(evt) {
if (evt.which === 13) {
$(evt.target).off("keyup");
$("<input class='barcode' type='text'/>")
.appendTo("#barcodes")
.focus()
.on("keyup", finishBarcode);
}
};
var submitBarcodes = function(evt) {
var barcodesArr = $(".barcode").map(function() {
return $(this).val();
}).get();
$("#display").text("Entered Barcodes: " + barcodesArr);
};
var $focusedInput = $('.barcode').on("keyup", finishBarcode).focus();
var $button = $('#submitAll').on("click", submitBarcodes);
});
input.barcode {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>Type barcode into input box</li>
<li>To enter barcode and allow new entry, press Return</li>
<li>To submit all barcodes, either press tab and then return or click Submit button</li>
</ul>
<div id="barcodes"><input type="text" class="barcode" /></div>
<div><button id="submitAll">Submit all barcodes</button></div>
<div id="display">Placeholder text</div>

Using HTML form field validation

I am using jQuery Mobile and am attempting to use HTML5 form field validation to perform inline form field validation. I am doing this because I really like the way that the browser reports issues in the bubble and I don't think it is very user friendly to wait until someone has completed filling out a form and then tell them what is wrong. Here is my HTML:
<form id="frmMain" action="#">
<input type="checkbox" data-enhance="false" value="1" id="cbxFB" />
<label for="cbxFB">
<span class="formsubtext">Check this box to use Facebook information to help fill out this registration. Once registered you will be able to use the Facebook login button.</span>
</label>
<label for="tbEmail">*Email</label><input type="email" id="tbEmail" required autofocus placeholder="example#address.com" />
<label for="tbPassword">*Password</label><input type="password" id="tbPassword" required />
<div class="formsubtext" style="margin-top:1px; padding-top:0px; margin-bottom:10px">Minimum of 6 characters, one capital character, and one lower case character.</div>
<label for="tbPasswordConfirm">*Password Confirm</label><input type="password" id="tbPasswordConfirm" required />
<label for="tbPin">*Account Pin</label><input type="password" pattern="[0-9]{4}" id="tbPin" required placeholder="####" />
<div class="formsubtext" style="margin-top:1px; padding-top:0px; margin-bottom:10px">A four digit number that you will remember. This value will be needed to perform sensitive tasks within the application.</div>
<label for="tbFName">*First Name</label><input type="text" id="tbFName" required />
<label for="tbLName">*Last Name</label><input type="text" id="tbLName" required />
<label for="tbPhone">Phone Number</label><input type="tel" id="tbPhone" pattern="\d{3}[\-]\d{3}[\-]\d{4}" placeholder="###-###-####" style="margin-bottom:1px; padding-bottom:0px;" />
<div class="formsubtext" style="margin-top:1px; padding-top:0px; margin-bottom:20px;">Used at your option when you schedule an appointment with a service provider</div>
<div style="display:none;"><label for="tbfbID">Facebook ID</label><input type="text" id="tbfbID" /></div>
<input type="submit" id="btnMainNext" data-icon="arrow-r" data-iconpos="right" value="Next" data-theme="c" class="ui-btn-c ui-btn ui-corner-all" />
</form>
For the confirm password form field I have the following event defined:
$("#tbPasswordConfirm").on("change", function (event) {
var password = $("#tbPassword").val();
var passwordconfirm = $("#tbPasswordConfirm").val();
if (password != passwordconfirm) {
$("#tbPasswordConfirm")[0].setCustomValidity("The value entered does not match the previous password entered.");
$("#btnMainNext").click();
}
else {
$("#tbPasswordConfirm")[0].setCustomValidity("");
}
$(this).focus().select();
})
My problem is that when the user enters something into the field and moves to the next field the HTML form validation shows the error message for the next field (which is required). I want it to show the message for the field they just left. How do I stop the focus from moving to the next field so that the bubble message that shows up is from the field they just entered the data into? As you can see I have tried setting the focus but that does not work. Any help would be greatly appreciated.
You can stop focus from moving to the next field but you can't trigger native validation UI or error message unless you click submit button.
To stop focus from moving next field, after you set the custom validity on the field, you can use:
$('#tbPasswordConfirm').blur(function(event) {
event.target.checkValidity();
}).bind('invalid', function(event) {
setTimeout(function() { $(event.target).focus();}, 50);
});
The blur() function will check the validity on blur and if it would be invalid, the corresponding function in bind() would set the focus back to that element.
Solved it
Fiddle
$(function() {
$("#tbPasswordConfirm").on("input", function(event) {
var thisField = $("#tbPasswordConfirm")[0],
theForm = $("#frmMain")[0],
password = $("#tbPassword").val(),
passwordconfirm = $(this).val(),
custom = password === passwordconfirm ? "" : "The value entered does not match the previous password entered.";
thisField.setCustomValidity(custom);
if (!theForm.checkValidity()) theForm.reportValidity();
});
});
You can use html tabindex attr to manipulate which element will get the focus when you click tab character. See docs to how to use it.
For example, if you make your password confirm input as tabindex="5", you can add tabindex="6" to the <label for="tbPin"> element to prevent next input from focusing right after.

Do not trigger form.$invalid on first load

Having such form
<div ng-controller="FormController as f_ctrl">
<form ng-submit="f_ctrl.submit()" name="myForm">
<input type="text" ng-model="f_ctrl.user.username"
required
ng-minlength="4"/>
<input type="text" ng-model="f_ctrl.user.password"/>
<input type="submit" value="Submit" ng-disabled="myForm.$invalid">
</form>
</div>
and such controller
.controller('FormController', [function() {
var self = this;
self.submit = function() {
console.log('User submitted form with ' + self.user.username)
}
}]);
I have a problem: when page first loads it immediately shows red border on username field, even before I start typing anything.
I need to highlight invalid fields only after first submission. Can this be done using form.$invalid ?
You have to use $pristine for that. It is true when form controller is not changed. so when you change textbox data its comes false.
Small example for you.
<div class="form-group" ng-class="{ 'has-error' : userForm.password.$invalid && !userForm.password.$pristine }">
<input id="passAnime" type="password" name="password" ng-model="user.password" class="form-control input-md" placeholder="Password" tabindex="5" ng-maxlength="25" ng-minlength="6" required>
<span ng-show="userForm.password.$dirty && userForm.password.$invalid">
<p ng-show="userForm.password.$error.required" class="error-messages">
Your password is required.
</p>
<p ng-show="userForm.password.$error.minlength" class="error-messages">
Your password is too short. Minimum 6 chars.
</p>
<p ng-show="userForm.password.$error.maxlength" class="error-messages">
Your password is too long. Maximum 25 chars.
</p>
</span>
</div>
Angular has helpers that tell you if the form (or form field) is $dirty (user has typed something) or if the form is $touched (the blur event has been triggered on the input). See this demo.
I need to highlight invalid fields only after first submission.
Unfortunately, Angular doesn't support that. But you could implement it yourself rather easily:
Controller
function FormController() {
var vm = this;
vm.submitAttempted = false;
vm.submit = function(isValid) {
if (isValid) {
// do stuff
}
else {
vm.submitAttempted = true;
}
};
}
HTML
<div ng-app='app'>
<div ng-controller='FormController as vm'>
<form name='fooForm' ng-submit='vm.submit(fooForm.$valid)' novalidate>
<label>Username</label>
<input
name='username'
type='text'
ng-model='vm.user.username'
required
ng-minlength='4'
ng-class="{'invalid': vm.submitAttempted && fooForm.username.$invalid}">
<br /><br />
<button type='submit'>Submit</button>
</form>
</div>
</div>
CSS
.invalid {
border-color: red;
}
Demo
I have a problem: when page first loads it immediately shows red border on username field, even before I start typing anything.
That's probably because you have the following CSS class:
.ng-invalid {
border-color: red;
}
Angular will always apply the ng-invalid class to fields that are invalid, and there's nothing you could do about that. So if you don't always want invalid fields to have a red border, you can't use that class and you should do it in a way similar to what I proposed above.
Also, check out ngMessages.
You can disable the default styling on the input field that is adding the red border by default, by adding the following CSS:
input:required {
-moz-box-shadow: none;
box-shadow: none;
}
Then if you want to highlight the field when the form is submitted, you will need to ensure that the form and form fields have relevant name attributes. Doing this will allow you to check if the field is valid or not and apply a class to your text field when it is invalid:
<input type="text" name="username" ng-class="{ 'invalid-field' : f_ctrl.myForm.username.$invalid && !f_ctrl.myForm.username.$pristine }" required />
f_ctrl.myForm and f_ctrl.myform.username will have additional properties that you can use/check to determine if the form or fields are invalid or not, or if they have been modified at any point (e.g. f_ctrl.myform.username.$dirty). You should be able to view these properties on your page by adding the follow HTML:
<div>
<pre>{{f_ctrl.myForm | json}}</pre>
</div>
Or, you could output self.myForm to the console from your controller to view it's properties
console.log(self.myForm);

Change input value on tab

I'm coding a small web app to log team members work time. It all works well, except one thing. When you tab on a fieldset a new page opens with a form to change the time for that person. The first time you tab it works, but when you click on the next fieldset it changes all input fields with the name 'begin-time' ?
I think i'm missing something but I'm not sure what it is.
I have the following form;
<form id="time-form">
<fieldset>
<div class="row">
<input type="text" value="Jonh Doe" id="fullname" name="fullname" readonly="">
<div class="time">
<input type="text" value="00:00" id="begin-time" name="begin-time" readonly="">
<input type="text" value="00:00" id="end-time" name="end-time" readonly="">
</div>
</fieldset>
<fieldset>
<div class="row">
<input type="text" value="Jane Doe" id="fullname" name="fullname" readonly="">
<div class="time">
<input type="text" value="00:00" id="begin-time" name="begin-time" readonly="">
<input type="text" value="00:00" id="end-time" name="end-time" readonly="">
</div>
</fieldset>
</form>
with the new form 'on tab';
<form id="add-time">
<input type="time" name="begin_time">
<input type="time" name="end_time">
</form>
and the javascript;
$$('#time-form fieldset').tap(function() {
var beginTime = $(this).find("[name='begin-time']");
$('#add-time input[name=begin_time]').change(function() {
beginTime.val(this.value);
});
$$('.add-time').tap(function() {
$('#addTimePage').addClass('pt-page-moveToRightEasing pt-page-ontop');
$('#timePage').addClass('pt-page-moveFromLeft pt-page-current');
setTimeout(function () {
$('#timePage').removeClass('pt-page-moveFromLeft');
$('#addTimePage').removeClass('pt-page-moveToRightEasing pt-page-ontop pt-page-current');
}, 400);
});
});
edit: I have setup a simple fiddle of the problem.
Okay, so I noticed a few problems:
Your first .click() call was targeting ALL time-form fieldsets when it should have only been targeting input fields.
Your .change() and second .click() are called inside the first .click() meaning the new methods will be called multiple times (because each use of .click() and .change() adds on to the actual event.
Your submit button wasn't actually submitting anything. It was just hiding itself.
To fix this, I gave each fieldset a class name of .fieldset-time so they can easily be looped through. I added an onclick() event to each <fieldset> to easily manipulate the one (and its children) that was clicked.
Here's the new JavaScript code:
// invoked each time an input with the onclick() attribute is clicked
function editTime(obj) {
$("#addTimePage").fadeIn();
$(obj).attr("id", "active"); // set id to active so we know this is the one we want to change
}
$("#submit").click(function() {
// get the new beginning and end times set by the user
var newBeginTime = $("#add-time input[name=begin_time]").val();
var newEndTime = $("#add-time input[name=end_time]").val();
// loop through all elements with class .fieldset-time and find the active one
$(".fieldset-time").each(function() {
if ($(this).attr("id") == "active") {
$(this).attr("id", "");
$("input[name=begin-time]", this).val(newBeginTime);
$("input[name=end-time]", this).val(newEndTime);
return false; // break out of the .each() loop
}
});
// finally, clear and hide the add time box
$("#add-time input[name=begin_time], #add-time input[name=end_time]").val("");
$("#addTimePage").fadeOut();
});
And the new JSFiddle: http://jsfiddle.net/J4Hjf/7/
I hope that's what you were looking for. :)

how can I add a wildcard with jquery binding

how can I add a wild card into this jquery bind event so that form fields with 'PauNumber' are ignored? This field is repeated for each entity. Unfortunately I can't easily assign a css class to it because the text box is created server side.
many thanks
<div class="PassengerWrapper">
<input type="text" value="" name="PauNumber0" id="PauNumber0">
</div>
<div class="PassengerWrapper">
<input type="text" value="" name="PauNumber1" id="PauNumber1">
</div>
<div class="PassengerWrapper">
<input type="text" value="" name="PauNumber2" id="PauNumber2">
</div>
$('.PassengerWrapper input[type=text], .PassengerWrapper select').not(':hidden').each(function () {
You can do it inside the .not('selector') to filter the elements you don't want
$('.PassengerWrapper input[type=text], .PassengerWrapper select').not(':hidden,input[name*=PauNumber]').each(function () {
You can use [name*=PauNumber] or [id*=PauNumber]
Here's an example fiddle for you http://jsfiddle.net/XQWmf/
Also link to the different selectors

Categories