Using jQuery.validate, how do you validate only a portion of the form when doing an AJAX callback? - ajax

I have a web page that has a few text boxes, and a dual list control. All of these data elements are for a particular entity. The form is for creating a new instance of this entity and saving it to the database. The dual list shows available people to use, and the user can move options from the available list to the selected list. All of this works perfectly when posted. There is a button at the bottom of the page to post the form.
To make things easy, I also want to include a hidden "form" that lets the user add a new person to the dual list without leaving the page. They click an "Add New" link which shows a previously hidden div. In the div are two text boxes: "emailName" and "emailAddress", and a button to click called "Add".
When the user clicks the "Add" button I need to validate the emailName and emailAddress fields, and only those two fields. If they are valid then I will make my AJAX request and handle the return data by adding a new option to the dual list.

Here's the solution I am using.
First, I disable validation of my partial's form elements and never re-enable it. I do this by specifying a class selector in the validator options using a custom script that's referenced in the main page.
Then, on my parital's button click I call validator.element for each element. If they are all valid then I perform the AJAX request.
Calling .element will show the validation message for the field and return a boolean indicating if it's valid. You have to check these carefully to avoid boolean operator short-circuiting issues, to make sure all the error messages get shown. I used the bitwise & to accomplish this.
var validator = $("#EmailRecipient_Name").closest("form").validate();
//validator.settings.defaultIgnoreClass is defined in a custom script, and set to ".ignoreValidation"
$("#EmailRecipient_Name").addClass(validator.settings.defaultIgnoreClass);
$("#EmailRecipient_Email").addClass(validator.settings.defaultIgnoreClass);
$("#addNewRecipientLink").click(
function () {
$("#addNewRecipientBox").toggle()
return false;
}
);
$("#addNewRecipient").click(
function(){
var validator = $("#EmailRecipient_Name").closest("form").validate();
if ( validator.element( "#EmailRecipient_Name" ) & validator.element( "#EmailRecipient_Email" ) )
{
$.post(
"#Url.Action( "Create", "EmailRecipient" )",
{
Name: $("#EmailRecipient_Name").val(),
Email : $("#EmailRecipient_Email").val()
},
function( data ){
if ( data.ErrorMessage )
{
alert( data.ErrorMessage );
}
else
{
$("#SelectedEmailRecipients").append("<option value='" + data.EmailRecipientID + "'>" + data.Name + "</option>");
$("#EmailRecipient_Name").val("");
$("#EmailRecipient_Email").val("");
}
}
);
}
return false;
}
);

Related

Filling MVC DropdownList with AJAX source and bind selected value

I have view for showing Member details. Inside there is an EditorFor element which represents subjects taken by the member.
#Html.EditorFor(m => m.Subject)
Inside the editor template there is a Html.DropDownListFor() which shows the selected subject and button to delete that subject
I am using an Html.DropDownListFor element as :
#Html.DropDownListFor(m => m.SubjectID, Enumerable.Empty<SelectListItem>(), "Select Subject",
new { #class = "form-control subjects" })
The second parameter(source) is set empty since I want to load the source from an AJAX request; like below:
$.getJSON(url, function (response) {
$.each(response.Subjects, function (index, item) {
$('.subjects').append($('<option></option>').text(item.Text).val(item.ID));
});
// code to fill other dropdowns
});
Currently the html loads before the dropdowns are filled. So the values of all subject dropdowns are set to the default "Select Subject". Is there a way around this or is it the wrong approach?
Note: There are a number of dropdowns in this page. That's why I would prefer to load them an AJAX request and cache it instead of putting in viewModel and filling it for each request.
** EDIT **
In AJAX call, the action returns a json object containing dropdowns used across all pages. This action is decorated with [Output Cache] to avoid frequent trips to server. Changed the code in $.each to reflect this.
You can initially assign the value of the property to a javascript variable, and use that to set the value of the selected option in the ajax callback after the options have been appended.
// Store initial value
var selectedId = #Html.Raw(Json.Encode(Model.Subject.SubjectID))
var subjects = $('.subjects'); // cache it
$.getJSON(url, function (response) {
$.each(response, function (index, item) {
subjects.append($('<option></option>').text(item.Text).val(item.ID));
});
// Set selected option
subjects.val(selectedId);
});
However its not clear why you are making an ajax call, unless you are generating cascading dropdownlists which does not appear to be the case. What you doing is basically saying to the client - here is some data, but I forgot to send what you need, so waste some more time and resources establishing another connection to get the rest of the data. And you are not caching anything despite what you think.
If on the other hand your Subject property is actually a collection of objects (in which case, it should be Subjects - plural), then the correct approach using an EditorTemplate is explained in Option 1 of this answer.
Note also if Subject is a collection, then the var selectedId = .. code above would need to be modified to generate an array of the SubjectID values, for example
var selectedIds = #Html.Raw(Json.Encode(Model.Subject.Select(x => x.SubjectID)))
and then the each dropdownlist value will need to be set in a loop
$.each(subjects, function(index, item) {
$(this).val(selectedIds[index]);
});
If your JSON tells you what option they have selected you can simply do the following after you have populated your dropdown:
$('.form-control.subjects').get(0).selectedIndex = [SELECTED_INDEX];
Where [SELECTED_INDEX] is the index of the element you want to select inside the dropdown.

How to bypass/dismiss webform validation in drupal 7?

Here is my situation:
I have a very long multi-page survey built by webforms in drupal.
The questions are not required but we don't want the users to skip all the questions too easy by just clicking Next Page button.
So this is what we need:
When the user try to click on "Next Page" button with any empty fields on the page, error or warning messages will show up, "Are you sure you want to skip this question?", as well as a skip button next to it. When the user click on the skip button, the message disappears and they click on the next page button to proceed the survey.
Here are my thoughts on this:
I used webform validation module to create an Not Empty validation and apply it to the fields.
in webform_validation_validators.inc:
case 'skip_if_empty':
foreach ($items as $key => $val) {
if (count($val) == 0) {
drupal_set_message(t('This field is empty.'), 'warning');
// do something, not sure about it here
}
}
Another thought:
I used the Dismiss module to display an X button next to the error message.
Can I add some functions to the X button to bypass the validation when it is clicked?
And here is the script for the Dismiss module, :
(function ($) {
Drupal.behaviors.dismiss = {
attach: function (context) {
$('.messages').each(function () {
var flag = $(this).children().hasClass('dismiss');
if (!flag) {
$(this).prepend('' + Drupal.t('Close this message.') + '');
}
});
$('.dismiss').click(function () {
$(this).parent().hide('fast');
// some functions to bypass validation to the field?
});
}
}
})(jQuery);
I don't know what to do to after the //. Or is there any other ideas that will work?
AS per the you requirement mention
Take this example
You have created webform having field like
Firstname with required field
Lastname with required field
Then Next button button
When user click next button then error show because you have make the fields are required
When your showing "Dismiss button" next to each field.
Whenr user click "Dismiss button" that time you have to remove "required" attribute of field using jquery or drupal ajax
After that when user click next button then user not get any kind of required field validation error.

Why disabled fields are not providing values on clicking submit in mvc3?

I have used Ajax.BeginForm / Html.BeginForm for a view which sends an object to the controller on clicking submit. There are some telerik controls which are disabled conditionally. On clicking submit, the object is unable to retrieve the already existing value in the control since it is disabled. Hence object is made with null values. Any help?
Im using jquery to disable these telerik controls on loading the page.
Change.setDropDownValues = function () {
if (condition) {
$("#A").data('tDropDownList').enabled = false; $("#A").data('tDropDownList').disable();
}
}
else if (condition) {
$('#Pop').attr('disabled', 'disabled'); //text box
$('#ShortDesc').attr('disabled', 'disabled'); //textarea
$('#LongDesc').attr('disabled', 'disabled'); //text area
$('#Cont').attr('disabled', 'disabled'); //text box
$('#iDate').attr('disabled', 'disabled'); //datepicker division
$('#C').data('tDropDownList').enabled = false; //drop down list
$('#C').data('tDropDownList').disable();
}
};
Can anyone say how to remodify so that I can fetch the disabled field values?
That's how disabled inputs work. They never send the value to the server. You could use readonly instead if you want to prevent the user from modifying the value and yet send the old value to the server when the form is submitted.
you can use something like this
$(":disabled", $('#yourform')).removeAttr("disabled");
before submit.

ajaxSubmit into current jQuery Tab

I know how to grab the index, but that doesn't appear to be what I need to post into the tab itself.
This is a continuation, but different question, from my previous post: Submiting jQuery form results back into dynamic tab
My tab form is submitting now with 100% success, internal to my jQuery validate, but I want my reply to appear in the tab it came from.
At the end of my jQuery validation I have:
submitHandler: function(form) {
var thisTab = $tabs.tabs('option', 'selected'); // what index are we?
var options = {
target: '#thisTab',
};
$(form).ajaxSubmit(options);
return false;
}
It's close, but what I'm doing is actually grabbing the index of the selected tab, this does not appear to be what I need for the ajaxSubmit to post into.
As I understand you want to set target to thisTab, but you are setting target as a jQuery selection string #thisTab,
this means target is the element with id "thisTab".
From Jquery Form Plugin API
target
Identifies the element(s) in the page to be updated with the
server response. This value may be specified as a jQuery selection
string, a jQuery object, or a DOM element. Default value: null
So you should set thisTab as the target.
Update : The main problem is that you are trying to set tab as target element, you should set the selectedPanel as target.
submitHandler: function(form) {
var thisPanel = $tabs.tabs('option', 'selectedPanel'); // what index are we?
var options = {
target: thisPanel,
};
$(form).ajaxSubmit(options);
return false;
}
Hum, maybe I wasn't clear and I'm not explaining it.
What I want is for the output of update.cfm to be shown in the same dynamic tab body that held the details I just updated. I tried what you suggested and all it does when I hit submit is blink. It does submit, I can use firebug to see the post and response, but the response is not shown. So I do want the tab as the target.
What you did do however is show me a new term "selectedPanel" that I did not know, and that lead me to this post which I had not seen before: How to get the selected tab panel element in Jquery UI Tabs?
And that led me to make the following change:
submitHandler: function(form) {
var selectedPanel = $("#tabs div.ui-tabs-panel:not(.ui-tabs-hide)");
var options = {
target: selectedPanel
};
$(form).ajaxSubmit(options);
return false;
}

JQuery Validate and Checkbox Click Function

I have a basic checkbox click function that only allows the user to click only one checkbox within each fieldset (there are four fieldsets each containing numberous checkboxes:
$(document).ready(function(){
$('input[type=checkbox]').click(function(){
// get the fieldset class
var fieldset = $(this).parents('fieldset').attr('class');
// set the number of checked
var numChecked = $('.'+fieldset+' input:checked').size();
// if more than 1
if(numChecked > 1){
alert('Please select only one option per breakout session.')
$(this).attr('checked',false);
}
});
Then I have a submit function on the form that will confirm that at least one checkbox is selected before posting the form:
$('form[name=mainForm]').submit(function(){
var error = '';
// loop through each fieldset
$('fieldset',this).each(function(){
// set the number of checked for this fieldset
var numChecked = $('input:checked',this).size();
// if none are checked
if(!numChecked){
// set the error var
error = 'At least one of your time sessions has no checkbox selected!';
// add class to show user
$(this).addClass('errorSessions');
}
else{
$(this).removeClass('errorSessions');
}
});
// if any errors, show them and don't allow the form to be submitted
if(error.length){
alert(error);
return false;
}
$("#mainForm").validate();
The form validates perfectly and everything happens flawlessly the first time around. The problem is that if you submit the form, the validation occurs and it gives the error "At least one of your time sessions has no checkbox selected!" - at that point if you proceed to select multiple checkboxes within a given fieldset that was not initially checked, it will ignore the checkbox click function and allow you to select more than one checkbox in a fieldset.
Can someone please help with this?
Okay, I figured it out. The error has to do with the script adding the class 'errorsessions' to the fieldset which changes the unique classname of the fieldset. By adding a unique id to each fieldset and then changing the script to reference .attr('id'); instead of .attr('class'); the issue resolved and the on click alert function resumed after the class was added.
Do you consider using radio buttons as they are there for single selection? This way you don't have to check for multi selection as it isn't possible for select more than one radio button in given group.

Resources