I am pretty new to javascript, and I am trying to work with mailgun's email validation feature and I am trying to get the validation to work (by ensuring the email data is intact prior to submission of a form.
https://github.com/mailgun/validator-demo
However I found that the function validation_success is always called asynchronously, resulting in the sequence as below:
checks start!
Feedback:390 checks complete! ErrorEmail=2
Feedback:347 execution begin
Feedback:404 validation begin! ErrorEmail=2
Feedback:419 validation complete! ErrorEmail=2
I want the sequence to be the following instead:
checks start!
validation begin! ErrorEmail=2 //this will update the ErrorEmail var.
validation complete! ErrorEmail=2
checks complete! ErrorEmail=2
execution begin
I have searched and tried all the techniques (async false/deferred/callbacks), but I can't seem to figure out what might have went wrong.
My code is as below:
var ErrorEmail = -1;
$(function () {
$('#User_Email').mailgun_validator({
api_key: 'x',
in_progress: validation_in_progress, // called when request is made to validator
success: validation_success, // called when validator has returned
error: validation_error, // called when an error reaching the validator has occured
});
$("#FeedbackForm").submit(function (event) {
if($("#User_Email").val())
{
check().done(function(){
console.log('execution begin');
if (ErrorEmail == 2) {
if (confirm('Are you sure this is the email you want to use?')) {
$(form).submit();
}
}
else if (ErrorEmail == 0)
{
$(form).submit();
}
});
event.preventDefault();
}
else
{
console.log('no email');
event.preventDefault();
}
});
});
function check(callback) {
var dfrd1 = $.Deferred();
console.log('checks start!');
dfrd1.resolve(
$('#User_Email').mailgun_validator({
api_key: 'x',
in_progress: validation_in_progress, // called when request is made to validator
success: validation_success, // called when validator has returned
error: validation_error, // called when an error reaching the validator has occured
}).done()
);
console.log('checks complete! ErrorEmail='+ErrorEmail);
return dfrd1.done().promise();
}
// while the lookup is performing
function validation_in_progress() {
$('#status').html("<img src=#Url.Content(#"~/Assets/img/loading.gif") height='16'/>");
}
// if email successfully validated
function validation_success(data) {
//var dfrd1 = $.Deferred();
//dfrd1.resolve(data);
console.log('validation begin! ErrorEmail=' + ErrorEmail);
$('#status').html(get_suggestion_str(data['is_valid'], data['did_you_mean']));
if (data['is_valid'] && !data['did_you_mean']) {
ErrorEmail = 0;
}
else if (data['is_valid'] && data['did_you_mean']) {
ErrorEmail = 2;
}
else
ErrorEmail = 1;
console.log('validation complete! ErrorEmail=' + ErrorEmail);
//return dfrd1.promise();
}
// if email is invalid
function validation_error(error_message) {
$('#status').html(error_message);
}
// suggest a valid email
function get_suggestion_str(is_valid, alternate) {
if (is_valid) {
ErrorEmail = 0;
var result = '<span class="success">Address is valid.</span>';
if (alternate) {
result += '<span class="warning"> (Though did you mean <em>' + alternate + '</em>?)</span>';
ErrorEmail = 2;
}
return result
} else if (alternate) {
ErrorEmail = 1;
return '<span class="warning">Did you mean <em>' + alternate + '</em>?</span>';
} else {
ErrorEmail = 1;
return '<span class="error">Email address is invalid. Please try another.</span>';
}
}
check() function already has a deferred object ($('#User_Email').mailgun_validator) the only thing to do is .pipe result of that function and call resolve function of dfrdl and in the end return dfrdl ONLY like below:
function check(callback) {
var dfrd1 = $.Deferred();
console.log('checks start!');
$('#User_Email').mailgun_validator({
api_key: 'x',
in_progress: validation_in_progress, // called when request is made to validator
success: validation_success, // called when validator has returned
error: validation_error, // called when an error reaching the validator has occured
}).pipe(function(res){
dfrd1.resolve(res);
})
console.log('checks complete! ErrorEmail='+ErrorEmail);
return dfrd1;
}
Related
I am trying to evaluate a form text/email field to see if there is something there and if so, run it past a regular expression valuation. It worked fine when I included the regex code in the SendEmail function with the rest of the logic but when I tried to move the regex part out into it's own function(validateEmailAddress), the validation still works but it doesn't seem to want to return false and just stop. Instead it continues on to the ajax part and sends the email regardless of whether it passes the regex test or not. It's the same code so I'm not sure why the "return false" doesn't work once the regex piece is moved out into it's own function.
Any thoughts are appreciated and THANK YOU!
function validateEmailAddress(address) {
filter = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,4})+$/;
if (!filter.test(address)) {
alert(address + ' - Is an invalid email address.');
return false;
}
}
function SendEmail() {
var emailFromVal = document.getElementById("EmailFrom").value;
var emailToVal = document.getElementById("EmailTo").value;
if (emailFromVal != 0) {
validateEmailAddress(emailFromVal);
} else {
alert("Please provide your email address.");
return false;
}
if (emailToVal != 0) {
}
else {
alert("Please provide your friend's email address.");
return false;
}
$.ajax({
method: 'POST',
url: '/_ajax/emailshare/',
dataType: 'json',
data: formCollection,
success: function (data) {
///send that email out
}
});
}
You are not doing anything with the return value from validateEmailAddress(), try this:
if (emailFromVal != 0) {
if(!validateEmailAddress(emailFromVal)){
return false;
}
} else {
alert("Please provide your email address.");
return false;
}
also, you need to return true from validateEmailAddress() when the email is valid:
function validateEmailAddress(address) {
filter = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,4})+$/;
if (!filter.test(address)) {
alert(address + ' - Is an invalid email address.');
return false;
}
return true;
}
return false; in validateEmailAddress will return just from validateEmailAddress, not from the enclosing function (SendEmail).
Your options are:
Check the return value of validateEmailAddress from the enclosing
function:
if(!validateEmailAddress(address)) return false;
OR
Throw from validateEmailAddress and catch the error from the
enclosing function (this'll allow the error to propagate up the
stack to an arbitrary length until you catch it--i.e., you don't
have to catch just from the enclosing function but also from its
caller or it's caller's caller, and so on and so forth).
I have this particular problem, where I need to validate the data before it is saved via an ajax call. save_ass_rub function is called when user navigates to a different URL.
In my application, I have a custom Window and user is allowed to input data. I am able to capture all the data in this step: var data = $('form').serialize(true);. But I need to loop through this and check if data for some specific elements is empty or not. I can't do it when the user is in the custom window. The Custom window is optional for the user. All I want is to alert the user in case he has left the elements blank before the data is submitted.
We are using Prototype.js and ajax .
<script>
function save_ass_rub() {
var url = 'xxxx';
var data = $('form').serialize(true);
var result;
new Ajax.Request( url, {
method: 'post',
parameters: data,
asynchronous: false, // suspends JS until request done
onSuccess: function (response) {
var responseText = response.responseText || '';
if (responseText.length > 0) {
result = eval('(' + responseText + ')');
}
}
});
if (result && result.success) {
return;
}
else {
var error = 'Your_changes_could_not_be_saved_period';
if (window.opener) { // ie undocked
//Show alert in the main window
window.opener.alert(error);
return;
}
return error;
}
}
// Set up auto save of rubric when window is closed
Event.observe(window, 'unload', function() {
return save_ass_rub();
});
</script>
Can some thing like this be done?
After Line
var data = $('form').serialize(true);
var split_data = data.split("&");
for (i = 0; i < split_data.length; i++) {
var elem = split_data[i];
var split_elem = elem.split('=');
if( split_elem[0].search(/key/) && split_elem[0] == '' ){
console.log( split_elem );
var error = 'Not all the elements are inputted';
window.opener.alert(error);
return;
}
}
Instead of using the serialized form string, I would use the form itself to do the validation. if $('form') is your form element then create a separate function that checks the form element so its compartmentalized.
function checkform(form)
{
var emptytexts = form.down('input[type="text"]').filter(function(input){
if(input.value.length == 0)
{
return true;
}
});
if(emptytexts.length > 0)
{
return false;
}
return true;
}
and in the save_ass_rub() function
//..snip
if(checkform($('form') == false)
{
var error = 'Not all the elements are inputted';
window.opener.alert(error);
return;
}
var data = $('form').serialize(true);
var result;
I only added text inputs in the checkform() function you can the rest of the input types and any other weird handling you would like to that function. As long as it returns false the error will be displayed and the js will stop otherwise it will continue
I am running a loop that updates records on a table but i need to wait for all of the records to update before i continue on.
How can I have jquery wait until all of the calls in the loopselectedrows function completes? I have read about .deferred and .when but i am not sure how to implement
either. they both do not seem to able to handle an array of calls if i where to change over to using an array for the ajax posts. Any help would be greatly appreciated.
this is the button that starts it all :
click: function () {
// validate all rows
var $selectedRows = $('#Table1').jtable('selectedRows');
LoopSelectedRows($selectedRows, 'Validate');
/// wait here until all ajax calls have completed
// then continue with checking
// check for any row with an error
var $ValidatedRows = $('#Table1').jtable('selectedRows');
var boolCheck = checkValidatedRows($ValidatedRows);
// if all records are succesfull then add them
// else alert user
if (boolCheck == true) {
LoopSelectedRows($selectedRows, 'Add');
}
else {
alert("Please correct invalid records and try again");
}
}
the first thing this does is take all of the records from the table and passes them to a looping function.
this is the looping function -
function LoopSelectedRows(SelectedRecords, actionType) {
if (SelectedRecords.length > 0) {
//Show selected rows
SelectedRecords.each(function () {
var record = $(this).data('record');
record.PERSON_NAME = record.PERSON_ID;
// Actions for loop
// Validation Action
if (actionType == 'Validate') {
check = validateRecord(record);
}
// call add function
if (actionType == 'Add') {
AddRecordToTable(record);
}
})
};
}
this loop can either validate or add records for now i am only worried about the validation function
this is the validation function:
function validateRecord(dataRecord) {
$.ajax({
url: "./ValidateAddRecord",
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(dataRecord),
success: function (data) {
if (data.Result == "OK") {
// update record with message
$('#table1').jtable('updateRecord', { record: data.Record });
}
else {
// display error
alert(data.Message);
}
}
});
}
One fairly clean way to know when multiple ajax calls are done is to use promises and jQuery's $.when(). That will give you a callback when all the ajax calls are done. It will take a little bit of reorganization of your code to use that.
First, you return the $.ajax() promise from validateRecord():
function validateRecord(dataRecord) {
return $.ajax({
url: "./ValidateAddRecord",
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(dataRecord),
success: function (data) {
if (data.Result == "OK") {
// update record with message
$('#table1').jtable('updateRecord', { record: data.Record });
}
else {
// display error
alert(data.Message);
}
}
});
}
Then, you collect all the promises in LoopSelectedRows() and return a master promise using `$.when():
function LoopSelectedRows(SelectedRecords, actionType) {
var promises = [];
if (SelectedRecords.length > 0) {
//Show selected rows
SelectedRecords.each(function () {
var record = $(this).data('record');
record.PERSON_NAME = record.PERSON_ID;
// Actions for loop
// Validation Action
if (actionType == 'Validate') {
promises.push(validateRecord(record));
}
// call add function
if (actionType == 'Add') {
promises.push(AddRecordToTable(record));
}
})
};
// return master promise
return $.when.apply($, promises);
}
Then, you can use that final promise to know when everything is done.
click: function () {
// validate all rows
var $selectedRows = $('#Table1').jtable('selectedRows');
LoopSelectedRows($selectedRows, 'Validate').then(function() {
// all the ajax calls in LoopSelectRows are done now
// check for any row with an error
var $ValidatedRows = $('#Table1').jtable('selectedRows');
var boolCheck = checkValidatedRows($ValidatedRows);
// if all records are succesfull then add them
// else alert user
if (boolCheck == true) {
LoopSelectedRows($selectedRows, 'Add');
} else {
alert("Please correct invalid records and try again");
}
});
FYI, you probably also want to change AddRecordToTable() to return a promise so it can work the same way (though it is not required because you aren't trying to wait for that operation to be done).
$.active returns the number of active Ajax requests. Use $.active==0 means no ajax requests are active. You could also use ajaxStart and ajaxStop to keep track of when requests are active.
Thank you jfriend00, your solution seems to have solved my issues.
Below is the updated version i am now using for anyone interested :
click: function () {
// validate all rows
var $selectedRows = $('#table1).jtable('selectedRows');
LoopSelectedRows($selectedRows, 'Validate').then(function () {
// check for any row with an error
var $ValidatedRows = $('#table1).jtable('selectedRows');
var boolCheck = checkValidatedRows($ValidatedRows);
// if all records are succesfull then add them
// else alert user
if (boolCheck == true) {
LoopSelectedRows($selectedRows, 'Add');
}
else {
alert("Please correct invalid records and try again");
}
});
}
// loop function
function LoopSelectedRows(SelectedRecords, actionType) {
var promises = [];
if (SelectedRecords.length > 0) {
//Show selected rows
SelectedRecords.each(function () {
var record = $(this).data('record');
// Actions for loop
// Validation Action
if (actionType == 'Validate') {
promises.push(validaterecord(record));
}
// call add function
if (actionType == 'Add') {
AddRecordToTable(record);
}
})
};
return $.when.apply($, promises);
}
// validate function
function validaterecord(dataRecord) {
var def = $.Deferred();
$.ajax({
url: "./ValidateAddRecord",
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(dataRecord),
success: function (data) {
if (data.Result == "OK") {
// update record with message
$('#table1).jtable('updateRecord', { record: data.Record });
// resolve token
def.resolve();
}
else {
// display error
alert(data.Message);
}
}
});
return def.promise();
}
I'm hoping this is just a simple fix due to me being a little dumb somewhere along the line. I'm executing my ASP.NET MVC login using AJAX. There is a "success" handler which returns a "true" value to the calling function which, in turn, load the home page.
The issue is that the "success" handler is executing BEFORE any value is returned - which means that nothing happens because the value is not "SUCCESS". I can confirm this by looking at the request in Firebug, the value returned is SUCCESS but nothing happens. If I apply a breakpoint to the end of the function and then continue execution it works just fine.
I have no idea what the issue is, I'd be very grateful for help or an explanation to what I'm doing wrong.
Thanks!
My JS Function:
function LogIn(UserName, Password) {
var Cont = true;
var ErrorString = "";
if (UserName == null || UserName == "") {
Cont = false;
ErrorString += "Username is Required.";
}
if (Password == null || Password == "") {
Cont = false;
ErrorString += "Password is Required.";
}
var result = false;
if (Cont) {
var LogInUrl = "/AJAX/LogIn?UserName=" + UserName + "&Password=" + Password;
$.ajax({
url: LogInUrl,
type:"GET",
success: function( data ){
if (data == "SUCCESS") {
result = true;
}
}
})
}
return result;
}
UPDATE: The function that calls the LogIn function:
$('#FormLogin').submit(function (e) {
e.preventDefault();
var UserName = $("#TxtLoginUsername").val();
var Password = $("#TxtLoginPassword").val();
var IsLoggedIn = LogIn(UserName, Password);
if (IsLoggedIn) {
window.location.assign("/");
} else {
$('#LoginErrorContainer').show();
$('#LoginErrorContainer .error-text').html("There was a problem logging you in. Please try again.");
}
})
As I said, the function does it's job and logs me in, but the "success" handler seems to execute before the value is returned.
Change your ajax call to something like this:
$.ajax({
url: LogInUrl,
type:"GET",
success: function( data ){
if (data == "SUCCESS") {
window.location.assign("/");
} else {
$('#LoginErrorContainer').show();
$('#LoginErrorContainer .error-text').html("There was a problem logging you in. Please try again.");
}
}
});
There is no point in returning result from LogIn, it'll always be false. You need to put the code handling the returned value in the callback.
Another alternative, if you don't like the idea of your LogIn function being so closely coupled to DOM manipulation is to return the promise from your ajax call. So at the end of LogIn, you'd do something like this:
return $.ajax({
url: LogInUrl,
type:"GET"
}
});
And then when you call it, you'd do something like this:
LogIn(UserName, Password).then(function(data) {
if (data == "SUCCESS") {
window.location.assign("/");
} else {
$('#LoginErrorContainer').show();
$('#LoginErrorContainer .error-text').html("There was a problem logging you in. Please try again.");
}
});
I have 3 ajax call in one function and checkAjaxCompletion which checks each ajax completion flag.
What the code below does is send multiple separate ajax calls and interval method checks completion flags to determine whether to proceed or keep interval. (I know clearInterval is not shown but the point is I want to use something other than interval)
Current code is:
function manyAjax() {
setInterval( function() { checkAjaxCompletion(); } , 200);
ajax1();
ajax2();
ajax3();
}
function ajax1() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax2() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax3() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function checkAjaxCompletion() {
if(ajax1_flag == 1 && ajax2_flag == 1 && ajax3_flag == 1) {
//everything went success, do some process
}
else if(ajax1_flag == 2 || ajax2_flag == 2 || ajax3_flag == 2) {
//some ajax failed, do some process
}
else {
//all ajax have not been completed so keep interval i.e. do nothing here
}
}
But I'm hesitating to depend on using interval function because calling it so often seem such waste of memory. There must be better way to do. I'm thinking if observer pattern can be applied here but would like to hear opinions.
It is observer-notifier, if you want to call it that - but each of your ajax calls will more than likely have a callback in javascript when they complete. Why not call checkAjaxCompletion() at the end of each of them, and do nothing if you're still waiting on others?
Dustin Diaz does a great job with this example.
function Observer() {
this.fns = [];
}
Observer.prototype = {
subscribe : function(fn) {
this.fns.push(fn);
},
unsubscribe : function(fn) {
this.fns = this.fns.filter(
function(el) {
if ( el !== fn ) {
return el;
}
}
);
},
fire : function(o, thisObj) {
var scope = thisObj || window;
this.fns.forEach(
function(el) {
el.call(scope, o);
}
);
}
};
The publisher:
var o = new Observer;
o.fire('here is my data');
The subscriber:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
To unsubscribe:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
// ajax callback
this.ajaxCallback = function(){
$.ajax({
type: "POST",
url: ajax.url,
data: {key: value},
async : !isAll,// false使用同步方式执行AJAX,true使用异步方式执行ajax
dataType: "json",
success: function(data){
if(data.status == 'successful'){
selfVal.parent().find('.msg').addClass('ok').html(msg.ok);
}else if(data.status == 'failed'){
checkRet = false;
selfVal.parent().find('.msg').removeClass('ok').html(msg.error);
}else{
checkRet = false;
}
return this;
}
});
}
return this;
Maybe you want to check your inputvalue callback ajax in your form;
You can view my website Demo, hope help you.
http://6yang.net/myjavascriptlib/regForm
Okay my idea was to make your own object that can handle sending an array of requests, keep a history of each request and do what i'm gonna call 'postProccessing' on each response, here is a probably very dodgy bit of code to hopefully demonstrate what I am thinking.
var Ajax = function() {
var request, callback, lst;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
request.onreadystatechange = handleResponse;
this.history = [{}];
this.send = function(args) {
for (var i = 0; i < args.length; i++) {
if (args.url) {
request.open(args.type || 'GET', args.url);
}
request.send(args.data || null);
callback = args.callback;
lst++;
}
}
function handleResponse() {
var response = {
url: '',
success: true,
data: 'blah'
};
history.push(response);
if (postProccess()) {
callback();
}
}
function postProcess() {
if (this.history[lst].success) {
return true;
} else {
return false;
}
}
}