I have a bit complex form (includes inputs, textareas, custom selects, etc). I want to perform validation (just to check whether all fields are empty or not). Nothing more.
But I find it difficult to validate whether a radio button was selected or not. I'm using Twitter Bootstrap and I have styled the radio buttons through their javascript and css (btn-group).
I want whenever a user types or clicks something to run the script which checks whether the field is empty or not.
I will post a jsFiddle link below which reproduces my problem. The javascript I use is a bit different, because I want to perform the check only to inputs in the current tab.
$('body').on('keyup mouseup ', 'li, label, input, textarea, select', function (e) {
var tabId = $(this).closest('.tab-pane').attr('id');
var inputs = $('#' + tabId + ' :input');
var errors = {};
inputs.each(function (i, element) {
if ($(element).attr('name') !== undefined) {
if ($(element).attr('type') !== 'radio') {
if ($.trim($(element).val()) === '') {
errors[i] = $(element).attr('name');
}
} else {
if ($('.active', $("input[name='" + $(element).attr('name') + "']").closest('.btn-group')).length <= 0) {
errors[i] = $(element).attr('name');
}
}
}
});
console.log(errors);
if (!$.isEmptyObject(errors)) {
$('a[href="#' + tabId + '"]')
.html("<i class='red ace-icon fa fa-times bigger-120'></i> " + $('a[href="#' + tabId + '"]').text());
} else {
$('a[href="#' + tabId + '"]')
.html("<i class='green ace-icon fa fa-check bigger-120'></i> " + $('a[href="#' + tabId + '"]').text());
}
});
http://jsfiddle.net/gzwyddrc/
To reproduce the problem:
Click on the text field (An alert will tell you that the form is not valid) - OK
Close the alert and type one letter (otherwise you will be annoyed by the alert). The alert will pop out again telling you that the form is still invalid. - OK
Now click on one of the radio buttons. The alert will still tell you that the form is invalid. - NOT OK
If you click on either the text field or one of the radio buttons the alert has something else to say: THE FORM IS VALID! - NOT OK
I believe I've misused the events that I binded to the elements I want to fire that validation.
Ok, I've looked into this, but there were quite a lot of changes I had to make.
This is the code:
$("form").on("keyup mouseup", function (ev) {
var selected, errors = [];
setTimeout(function () {
$("input,select").each(function (i, v) {
var e;
e = $(v);
if (e.attr("name") === undefined) return;
switch (e.attr("type"))
{
case "radio":
selected = false;
e.closest(".btn-group").find("input[type=radio]").each(function (i, v) {
if ($(v).closest("label").hasClass("active"))
{
selected = true;
}
});
if (!selected) {
errors.push(e.attr("id"));
}
break;
default:
if ($.trim(e.val()) === "")
{
errors.push(e.attr("name")); // should be id?
}
break;
}
});
if (errors.length > 0) {
alert("ERRORS: " + errors);
}
}, 10);
});
The changes I made are:
event handlers are attached to the form, this is more convenient especially for multi-form pages (imagine a separate form on the top for login);
the selector also considers select (dropdowns) a possible input field;
minor name/order changes to make it more readable;
the switch replaces the if, because you will encounter more input types further along (switch scales better than if..else);
replaced the error object with an error array on which to push() errors;
when a radio group is unselected, the whole group is invalid, not any single one of the radio buttons nested, so the check should be based on the group as a whole (see use of selected flag);
for radio buttons the active class is toggled on the label not on the input;
finally, the most important feature you'll already have noticed:
Bootstrap itself uses events and JS to toggle the active class, so if you check it right away the label will never have the active class -- to counter this, I inserted a setTimeout() that will fire validation 10 ms later (which still is instantly for humans) so that Bootstrap has all the time to make an update pass over the form before we go in and validate.
I checked it thoroughly in a fiddle, so I'm quite confident it works well and opens up many possibilities you've probably envisioned.
Related
Is it possible to identify if the value of radio button has not changed?
Currently I am trying to change the confirmation message of submit button on button changed, and do not want any message if the value has not changed. I have something like this now:
$('input[type="radio"]').change(function() {
var selected = $('input:checked[type="radio"]').val();
if(selected == 'true') {
$("#submit_button").data("confirm", "foo");
} else if(selected == 'false') {
$('#fee').hide();
$("#submit_button").data("confirm", "bar");
}
This will change confirm message to foo if button selected is true, and bar if button selected is false. However, what if I want to return nothing (no message), if radio button by default is true, and selected is true?
You can start a variable outside the event:
var radioChanged = 0;
And, in your event increase it:
$(':radio').change(function() {
radioChanged += 1;
// your code ...
});
Then, later on:
if (radioChanged > 0) {
alert('Change function occurred ' + radioChanged + ' times.');
} else {
alert('Radio button not changed.');
}
As i understand your expected behaviour, check if any radio has no more its default checked value:
$('form').on('submit', function() {
var anyRadioChanged = !!$(this).find('input[type="radio"]').filter(function() {
return $(this).is(':checked') != this.defaultChecked;
}).length; // '!!' to get boolean but it doesn't really matter here
if(anyRadioChanged) {
// show message(???)
}
})
you can hide message element just adding display: none to it or use jquery hide method
$('#someElementId').hide();
or
$('#someElementId').css("display","none")
I have a button that is created on each slide in a quiz game. Radio buttons containing the answer choices are appended from an object onto each slide as you cycle through the questions. I want to require that a radio button be clicked on before you can access the nextQuestion button. You can find the .append() on line 5 of the code below (inside of the loadQuestion function). What method would be the best way to achieve the desired result? If you need more of the code, let me know.
var loadQuestion = function (){
$('.question-name').html(name + (qnum) +"/"+ total);
$('.question').html(questions[count].question);
for(var i=0; i<questions[count].options.length; i++) {
$('.inputs').append('<input type="radio" name="question" value="'+questions[count].options[i]+'">'+questions[count].options[i]+'<br>')
}
};
/*--- First Question ---*/
var name = "Question ";
var qnum = 1;
var count = 0;
var total = questions.length;
loadQuestion();
/*--- When the Next Question Button is Hit ---*/
nextQuestion.click(function() {
$('.inputs').html("");
qnum++;
count++;
if (qnum <= 4) {
loadQuestion();
} else if (qnum == 6) {
$('.question-name').html("Your Score:");
$('.question').html("You got X out of 5 questions correct!");
nextQuestion.html("Home Screen").click(function() {
location.reload();
});
} else if (qnum == 5){
loadQuestion();
$('.next-question').html("Get Score!");
}
});
$(document).ready(function () {
$('#nextButton').attr('disabled', true);//disable the button by default on page load
$("input[type=checkbox]").on("click", function () {
if (this.length > 0) {
$('#nextButton').attr('disabled', false);//enable only when the checkbox is checked
}
});
});
I hope this helps!
Security note: Anybody can remove the disabled attribute from the button tag using developer tools in the browser. Use the backend to validate the checkbox value.
There's more than one way to go about this:
"Prevent button press until radio is selected"
From a ui/ux perspective your request raises the following question: "If the user isn't supposed to click on the button until the radio is selected, why is the button available for them to press before the radio is selected?" So, let's start there.
//pseudo-code - use delegate binding '.on()' for dynamically generated elements
$('.inputs').on('click', 'input[name="question"]', function({
if ($(this).is(':checked')) {
$('#nextButton').attr('disabled', false);
} else {
$('#nextButton').attr('disabled', true);
} /*... snip ...*/
}));
Or, you could generate the nextButton after an answer is selected much in the same way that you are currently generating the radio button - just remember to use delegate event binding. This is probably the "better way" because as has already been pointed out by #zadd, the disabled property can be circumvented.
Without reinventing the wheel, you could also just check to see if there's a radio selected when the button is pressed.
// pseudo-code again
nextQuestion.click(function() {
if($('input[name="question"]:checked').length > 0){
// checked!!! go do stuff!!!
} else {
// not checked! i should probably throw an alert or something...
alert('please answer the question before proceeding...');
}
});
I have a select box called "requestHistoryRequestType". I'm trying to write some jQuery so that when the value of that select box is changed I call a function that adds a class and attribute to a field and appends a span to the field that I pass in as a parameter.
The problem is if a user chooses EXPAPP or EXPDEN but then changes their selection to NA it should remove the added stuff from the previous fields and add the same stuff to a different field. Kinda hard to explain, but ask questions away! I'm kinda new to writing complex jQuery like this.
The function that does the adding classes and such:
function requiredField(requiredField) {
$(requiredField).parent().addClass('has-error');
$(requiredField).attr('data-rule-required', true);
$("label[for='" + requiredField.replace('#', '') + "']").append("<span style='color:#b94a48;' class='has-error has-tooltip' data-placement='right' title='Required Field'>*</span>");
}
The actual on change listener:
//Validations for EXPAPP, EXPDEN, and NA
$("#requestHistoryRequestType").on("change", function() {
if ($("#requestHistoryRequestType").val() === "EXPAPP" || $("#requestHistoryRequestType").val() === "EXPDEN"){
requiredField("#requestHistoryVerbalDateTime");
requiredField("#requestHistoryWrittenDateTime");
} else if ($("#requestHistoryRequestType").val() === "NA") {
requiredField("#requestHistoryComments");
}
});
Thanks Stack!
Create a function that would remove the added stuff from all fields and call it before requiredField() calls:
function removeRequiredFields()
{
var $fields = $("#requestHistoryVerbalDateTime, #requestHistoryWrittenDateTime, #requestHistoryComments");
$fields.parent().removeClass('has-error');
$fields.attr('data-rule-required', false);
$fields.each(function() {
$("label[for='"+$(this).attr('id')+"']").find("[title='Required Field']").remove();
});
}
Or you can pass $fields from the event handler to removeRequiredFields() instead of hardcoding it there, for added flexibility.
I would just have a separate function for when you select a "NA" rather then trying to build that functionality into the same function.
I'll rewrite your event handler to make it a bit cleaner as well (IMO).
//Validations for EXPAPP, EXPDEN, and NA
$("#requestHistoryRequestType").on("change", function() {
var selectedVal = $(this).val();
if (selectedVal === "EXPAPP" || selectedVal === "EXPDEN"){
requiredField("#requestHistoryVerbalDateTime");
requiredField("#requestHistoryWrittenDateTime");
} else if (selectedVal === "NA") {
requiredField("#requestHistoryComments");
}
});
This way you are not hitting the DOM a potential 3 time to test your conditions every time an event is triggered. A minor change but probably a useful one as you get into more complex and larger jQuery selectors.
Edit: If you feel you MUST do it in one function then you can call the function with both elements you want to append
function requiredField(requiredField1, requiredField2) {
if (requiredField2 != null){
$(requiredField1,requiredField1).parent().addClass('has-error');
$(requiredField1,requiredField1).attr('data-rule-required', true);
var requiredLabel = "<span style='color:#b94a48;' class='has-error has-tooltip' data-placement='right' title='Required Field'>*</span>"
$("label[for='" + requiredField1.replace('#', '') + "']").append(requiredLabel);
$("label[for='" + requiredField2.replace('#', '') + "']").append(requiredLabel);
}
else {
//remove multiple element classes and add it to the single one representing the "NA"
}
}
This is based on you only ever having one case where you would be passing a single "requiredField" on a case of a "NA"
I need to change the back button functionality of my phonegap project, which I've succeeded in doing without any problem. The only issue now, is that I need to further change the functionality based on if the user has a certain field selected.
Basically, if the user has clicked in a field with the id of "date-selector1", I need to completely disable the back button.
I was attempting to use document.activeElement, but it only returns the type of the element (input in this case), but I still want the functionality to work when they are in a general input, but not when they are in an input of a specific id.
EDIT
I tried all of the suggestions below, and have ended up with the following code, but still no success.
function pluginDeviceReady() {
document.addEventListener("backbutton", onBackKeyDown, false);
}
function onBackKeyDown() {
var sElement = document.activeElement;
var isBadElement = false;
var eList = ['procedure-date', 'immunization-date', 'lab-test-done', 'condition-onset', 'condition-resolution', 'medication-start-date', 'medication-stop-date', 'reaction-date'];
console.log("[[ACTIVE ELEMENT: --> " + document.activeElement + "]]");
for (var i = 0;i < eList.length - 1;i++) {
if (sElement == $(eList[i])[0]) {
isBadElement = true;
}
}
if (isBadElement) {
console.log('Back button not allowed here');
} else if ($.mobile.activePage.is('#main') || $.mobile.activePage.is('#family') || $.mobile.activePage.is('#login')) {
navigator.app.exitApp();
} else {
navigator.app.backHistory();
}
}
if you're listening for the back button you can add this if statement:
if (document.activeElement == $("#date-selector1")[0]) {
/*disable button here, return false etc...*/
}
or even better (Thanks to Jonathan Sampson)
if (document.activeElement.id === "date-selector1") {
/*disable button here, return false etc...*/
}
You can have a flag set when a user clicks on a field or you can have a click event (or any other type of event) when a user clicks on the field that should disable the back button.
From the documentation it looks like for the specific page that the backbuton is conditional on you can drop back-btn=true removing that back button.
http://jquerymobile.com/test/docs/toolbars/docs-headers.html
If you need complex conditional functionality you can just create your own button in the header or footer, style it using jquery-mobile widgets and implement your own click functionality.
I have listview with two checkboxes in itemtemplate.
I want to validate that user can only select only one checkbox in each row.
The behaviour you're describing is accomplished using standard HTML radiobuttons. If you change your design to use these you'll get the benefit that
The user can only select a single item, no extra javascript needed
Users expect to be able to choose multiple checkboxes but only a single radiobutton IE you're working with their expectations
If you're still sure you want to use jQuery then something like this should do it.
$(':checkbox').change(function(){
if($(this).attr('checked')) {
$(this).siblings(':checkbox').attr('checked',false);
}
});
#vinit,
just a little change, you forgot the else part,
$('input:checkbox[id*=EmailCheckBox]').click(uncheckOthercheckbox);
$('input:checkbox[id*=SMSCheckBox]').click(uncheckOthercheckbox);
function uncheckOthercheckbox() {
if (this.id.indexOf("EmailCheckBox") != -1) {
var otherCheckBoxId = this.id.substring(0, this.id.indexOf("EmailCheckBox")) + "SMSCheckBox";
}
else {
var otherCheckBoxId = this.id.substring(0, this.id.indexOf("SMSCheckBox")) + "EmailCheckBox";
}
var i = "#" + otherCheckBoxId;
if (this.checked) {
$(i).removeAttr('checked');
}
else {
if ($(i).attr('checked') === false) {
$(i).attr('checked', 'checked');
}
}
}
Thanks for the reply. had also asked one of my friend and he gave me the following solution which is working fine. Posting it, if anybody needs it.-
say ur checkboxes in the 2 clumns are named EmailCheckBox and SMSCheckBox
then use this code to toggle the checkboxes in each single row:
$('input:checkbox[id*=EmailCheckBox]').click(uncheckOthercheckbox);
$('input:checkbox[id*=SMSCheckBox]').click(uncheckOthercheckbox);
function uncheckOthercheckbox() {
if (this.id.indexOf("EmailCheckBox") != -1) {
var otherCheckBoxId = this.id.substring(0, this.id.indexOf("EmailCheckBox")) + "SMSCheckBox";
}
else {
var otherCheckBoxId = this.id.substring(0, this.id.indexOf("SMSCheckBox")) + "EmailCheckBox";
}
var i = "#" + otherCheckBoxId;
if (this.checked) {
$(i).removeAttr('checked');
}
}