Why is this variable changing when passing it around functions? - javascript

Edit2: Yay, found the problem, there is actually an error in the ajax call, and because of my stupidity, I didn't realise that both the methods - success and error can be ran (I thought it was either one or the other), so formComplete was being set to false every time because there was an error.
Appreciate the time you gave & tip about not using global variable names as function parameters.
Edit: Here's the code where formComplete is set (console.log()'s to check formComplete throughout the process):
validate: function(field) {
if(!field.val()) {
formComplete = false;
// formComplete is false here
console.log(formComplete);
}
else {
if(field.attr('name') === 'queryEmail') {
// Validate the email
if(DMOFFAT.helper.validateEmail(field.val()) === true){
// formComplete is either true or false here, depending on the last validation carried out
console.log(formComplete);
formComplete = true;
// formComplete is true here
console.log(formComplete);
}
else {
formComplete = false;
// formComplete is false here
console.log(formComplete);
}
}
else {
formComplete = true;
// formComplete is true here
console.log(formComplete);
}
}
},
Question: Why is this variable (formComplete) going from true to false?
I've written some basic form validation for a contact form, here's how I've done it:
Defined the fields like so:
var queryTypeField = $('#queryType'),
queryMessageField = $('#queryMessage'),
queryEmailField = $('#queryEmail'),
queryNameField = $('#queryName'),
submitButton = $('#submit');
Adding some event handlers to these like so (FWIW, DMOFFAT variable is just an object which holds different modules of the code e.g. contactForm = contact form javascript etc.):
queryMessageField.on('blur', function() {
DMOFFAT.contactForm.validate(queryMessageField);
});
queryNameField.on('blur', function() {
DMOFFAT.contactForm.validate(queryNameField);
});
queryEmailField.on('blur', function() {
DMOFFAT.contactForm.validate(queryEmailField);
});
submitButton.on('click', function(evt) {
evt.preventDefault();
console.log('Click');
console.log(formComplete);
DMOFFAT.contactForm.send(formComplete);
});
The validate function simply sets 'formComplete' to either true or false, depending on if the field is valid or not.
When my fields are all filled in correctly, formComplete = true.
As you can see from the last line of my code above, I pass formComplete (which is true) over to my send function. My send function simply checks the value of formComplete, and either sends the data off to a php script, or prints an error, here's the code:
send: function(formComplete) {
// This is true when the form is filled in correctly
console.log('In send formComplete is...' + formComplete);
if(formComplete === true) {
// Extract form values
formData['queryMessage'] = queryMessage.value;
formData['queryType'] = queryType.value;
formData['queryName'] = queryName.value;
formData['queryEmail'] = queryEmail.value;
$.ajax({
type: 'POST',
async: true,
url: '....',
dataType: 'json',
data: formData,
success: function(data, status, xhr) {
DMOFFAT.contactForm.writeMessage(formComplete);
},
error: function(xhr, status, err) {
DMOFFAT.contactForm.writeMessage(formComplete);
}
});
}
else {
this.writeMessage(formComplete);
}
Now, I KNOW that formComplete is true when the form is filled in correctly, because my php script creates a .txt file with the data in, if it was false, this file wouldn't be created.
This means that we send the value of formComplete off to writeMessage, which simply writes out some HTML to the page to display whether the submission was successful or not, here's the code:
// Disgusting spaghetti code
writeMessage: function(formComplete) {
// This is false now...
console.log('In writeMessage formComplete is...' + formComplete);
if(formComplete === true) {
contactFormElement.html('<div class="success ui-message cf-message"><p><strong>Thank you</strong> for your query, we\'ll get back to you as soon as we can.</p></div>');
}
else {
// Check if there's already an error, otherwise many will appear
if(errorElement === '') {
errorElement = '<div class="error ui-message cf-message"><p>' + this.config.errorMsg + '</p></div>';
contactFormElement.prepend(errorElement);
}
}
}
formComplete itself is defined like so:
var formComplete;
When I inspect formComplete on the first line of writeMessage, it's now false, I cannot find out why though...even when I explicitly set formComplete to true before it's passed to writeMessage, it's still false.
TLDR: Tell me where I'm being stupid please :)
PS: I know I could use a pre-built contact form validation plugin, but wanted to try build something simple myself.

The problem is, that you are calling writeMessage() from a callback function for your AJAX request, so the interpreter is looking for a global variable on execution time. Anyway, you can simply pass true to writeMessage() in your callback functions, as the calls are only executed if formComplete is true-

Related

Why is my function returning “undefined” instead of boolean

$(document).ready(function() {
$("form").submit(function(e) {
if (!checkStockOfProduct())
{
e.preventDefault();
return false;
}
return true
});
});
<script src="~/Scripts/storeinputoutput.js"></script>
storeinputoutput.js file:
function checkStockOfProduct() {
var allowSubmitForm = true;
$("table#StoreItemdatatable > tbody > tr").each(function () {
.
.
.
var storeId = $('#StoreID').val();
var stock = null;
var URL = '/aaa/bbb'
$.ajax({
async: false,
url: URL,
contentType: 'application/x-www-form-urlencoded',
dataType: 'json',
data: {
productNServiceID: productNServiceID,
storeID: storeId
},
type: 'POST',
success: function (data) {
stock = data.Stock;
}
, error: function (jqXHR, exception) {
}
});
if (...) {
allowSubmitForm = false;
}
return allowSubmitForm;
});
}
In form submit , I called the function and I wouldn't do the submit operation if function return false.
But the value of the xx variable is always undefined.
Please advise
Checked using Alert. variable "allowSubmitForm" in function "checkStockOfProduct" in the last line has value and not "undefined"
But in Submit it is undefined
I understand you want to return boolean, so use true and false rather than 'true' and 'false'
Why? The ones without quotes are boolean while the ones with quotes are string. A non-empty string in javascript would always return true while an empty string would return false (youare returnimg non-empty strings there and the result is obviously not what you would want in this case).
var is a little tricky and I would suggest we use let next time. Since it doesnt seem as though you are doing a lot in the checkStockOfProduct function I would refactor it to ==>
const checkSumOfProduct = (whatever...) ? false : true
I noticed the update on your question, I really don't get what you are trying to do there but to me it looks as though the result of the checkStockOfProduct decides whether you would prevent default form submission on submit and return false or not.
I would also be assuming that the CheckSumOfProduct function is synchronous
Let's refactor that code to do the same thing you were trying to do but look something like this ==>
$(document).ready(function() {
$("form").submit(function(e) {
if(!CheckStockOfProduct()){
e.preventDefault()
return false
}
return true
});
});
Let me know if this works out...I am in transit and on mobile atm
Try
function checkStockOfProduct() {
var allowSubmitForm = true;
if (...) {
allowSubmitForm = false;
}
return allowSubmitForm;
};
And adjust your submit() event handler based on the function return value:
$(document).ready(function () {
$("form").submit(function (e) {
if (checkStockOfProduct()) {
//valid
return;
}
//invalid
e.preventDefault();
});
});

jquery / javascript Load different content depending on session

hey guys i have this code here:
$('#internet').click(function(e){
e.preventDefault();
$.ajax({
url: "ajax/sessionset.php",
success: function (data){
if (data == 1){
$.ajax({
type: "POST",
//add variables
url: "ajax/loggedin.php",
success: function(data2){
//history.pushState({"internet.php?view=internetlog");
$('#internetlog').html(data2);
}
});
}
else if(data===0){
alert("suka");
}
}
});
});
The sessionset.php returns a value of either 1 or 0, depending if the session is currently going on or not.
Problem here is the link $('#internet')
returns the url loggedin.php when the data value is 1.
However if the data value is 0, nothing happens, since the e.preventDefault(); prevents any events.
Already checked on firebug that it either returns values of 1 or 0, I dont understand why the alert is not firing off when the value returned is 0...
edit: just checked the sessionset.php in a separate window instead of firebug
<?php
session_start();
if (!empty($_SESSION['origuserip'] && $_SESSION['loggedin'])){
$switch = "1";
}
else {
$switch = "0";
}
echo $switch;
the return value of 1 is 1 however if !empty is false it returns
Notice: Undefined index: origuserip in ajax\sessionset.php on line 4
0
SOLUTION:
Guess the simplest way is just the best way -_-
else {
("suka");
}
The scripts return value is probably a string, because you didn't specify the return type of your AJAX call.
You should validate like this: data==="1" and data==="0". Which checks for identity, as long as you definitely return strings.
data==1 is always true, if it's set and not null.
Regarding the other problem:
Make sure your $_SESSION variables are set properly when you check their indexes and separate the empty() checks. For example like this:
if (!empty($_SESSION['origuserip']) && !empty($_SESSION['loggedin'])){
$switch = "1";
}
else {
$switch = "0";
}
echo $switch;

jQuery Validation with promises

I'm using the jQuery Validation plugin for a signup form and trying to check if an email address is already taken as part of the validation. The problem is that the check happens via a promise, and I don't know how (or if) I can make this work with the validation plugin. Here's what I have currently:
$("#signup form").validate({
rules: {
emailSignup: {
email: true,
required: true,
remote: checkAvailable
}
}
});
function checkAvailable() {
var email = $("#emailSignup").val(),
available;
App.isEmailAvailable(email)
.then(function(response) {
available = response;
})
.error(function() {
available = response;
});
setTimeout(function() {
if (available == true) {
console.log("is available");
return true;
} else {
console.log("not available");
return false;
}
}, 100);
}
The setTimeout is just a hacky way to ensure I have the response before I try to log it (I know that's terrible, but it's just for testing).
The thing is, this will correctly log is available or not available depending on the email address I enter, so it works up to that point. But I can't seem to actually return true/false back up to the remote method so that it kicks off the error handling. So what happens is anything that's a syntactically valid email gets marked as valid, even if it's logging not available based on the response.
Is this at all possible?
Update: I also tried doing this in a custom method:
jQuery.validator.addMethod("email", function(value, element) {
var field = this,
available;
App.isEmailAvailable(value)
.then(function(response) {
available = response;
})
.error(function() {
available = response;
});
setTimeout(function() {
if (available == true) {
console.log("is available");
return field.optional(element) || /^[\w-+\.]+#([\w-]+\.)+[\w-]{2,4}$/.test(value);
} else {
console.log("not available");
return false;
}
}, 100);
}, jQuery.validator.format("Please enter a valid email address."));
So the idea here is it would check if the address is available, and if it is, then it would check that it's syntactically valid. Again, it correctly logs is available/not available based on the address I enter, but doesn't return true/false properly to mark the field as valid or invalid.
Based on the "remote" jquery validate rule :
$.validator.addMethod('users_email_exists', function (value, element) {
var method = 'remote';
var previous = this.previousValue(element, method);
var validator = this;
if (!this.settings.messages[element.name]) {
this.settings.messages[element.name] = {};
}
previous.originalMessage = previous.originalMessage || this.settings.messages[element.name][method];
this.settings.messages[element.name][method] = previous.message;
var optionDataString = $.param({data: value});
if (previous.old === optionDataString) {
return previous.valid;
}
previous.old = optionDataString;
this.startRequest(element);
new Promise(function (fulfill) {
// YOUR STUFF, YOUR AJAX GET/POST REQUEST AND URL WITH PARAMS
$.get('/backend/users/ajax/filtered-users-list', {email: value})
.done(function (data) {
// YOUR STUFF TO VALIDATE DATA
// IF VALID TRUE -> validation success
// IF VALID FALSE -> validation failure
var valid = !data.length;
fulfill(valid);
})
}).then(function(valid) {
validator.settings.messages[ element.name ][ method ] = previous.originalMessage;
if ( valid ) {
submitted = validator.formSubmitted;
validator.resetInternals();
validator.toHide = validator.errorsFor( element );
validator.formSubmitted = submitted;
validator.successList.push( element );
validator.invalid[ element.name ] = false;
validator.showErrors();
} else {
errors = {};
message = validator.defaultMessage( element, { method: method, parameters: value } );
// YOUR STUFF, YOUR VALIDATION MESSAGE HERE
errors[ element.name ] = previous.message = 'EMAIL ALREADY ASSIGNED TO AN USER';
validator.invalid[ element.name ] = true;
validator.showErrors( errors );
}
previous.valid = valid;
validator.stopRequest( element, valid );
});
return "pending";
},
"EMAIL ALREADY ASSIGNED TO AN USER"
);
Then call your custom rule :
$("#signup form").validate({
rules: {
emailSignup: {
email: true,
required: true,
users_email_exists: true
}
}
});
Include this script as Promise class reference :
<!-- promise -->
<script src="https://www.promisejs.org/polyfills/promise-7.0.4.min.js"></script>
<script src="https://www.promisejs.org/polyfills/promise-done-7.0.4.min.js"></script>
The function that you've passed to setTimeout() will execute in future (a.k.a asynchronously) - after your checkAvailable() is completed. So its returning value is meaningless for the checkAvailable().
You should do rather the following:
DisableTheForm();
App.isEmailAvailable(value)
.then(function(response) {
$("#signup form").validate();
if( it is valid) {
EnableTheForm();
PostFormData();
}
})
.error(function() {
CryAsItIsNotAvailable();
EnableTheForm();
});
So to do your validation in response of positive feedback of your isEmailAvailable
You cannot use the remote method because it's looking for a URL parameter to access "remotely" via ajax().
You obviously would not call a JavaScript function with ajax(), so using remote to call a JavaScript function makes no sense.
You might be able to create a custom function using the .addMethod() method. However, you will have issues if any part of that is performed asynchronously as the custom rule will be evaluated before you have the result.

ajax success callback executes out of expected order

I have a function that validates some fields when a button is pressed. First one checks if the username and password are authentic or not. then if the password is appropriately secure. Then if it matches the confirm-password box. However, it seems that the ajax that check to see if the user is authentic does not complete before the alert in the first function pops up.
$(document).ready(function() {
$('#submit_pw_ch').on('click', function(){
var alertString = "Please correct the following errors: \n"
//current username and password are correct
var vUsr = valUsr();
//new password is sufficiently secure
var vPwd = valPwd();
//confirmation of new password is same as previous box
var sPwd = samePwd();
console.log('valid user : ' + vUsr + ' valid password : ' + vPwd + ' same password : ' + sPwd);
//append appropriate warnings to alert string
if ( !vUsr ) { alertString += "-Your current username and password are invalid. \n"; }
if ( !vPwd ) { alertString += "-The new password you have selected is not strong enough. \n"; }
if ( !sPwd ) { alertString += "-The confirmation of your new password does not match the previous entry. \n"; }
if ( !vUsr || !vPwd || !sPwd ) {
alert(alertString);
return false;
} else {
//change password
}
});
});
So the line that checks for that is var vUsr = valUsr(); which calls
function valUsr() {
var un = $('#uNameInput').val();
var pw = $('#uPwdInput').val();
//return value
var validUsr = false;
$.ajax({
type: "post",
url: "queries/confirm_user.php?<?=time()?>",
data: "un=" + un + "&pw=" + pw,
dataType: "json",
success: function (returnedData) {
console.log(returnedData)
if (data == 'true') {
validUsr = true;
} else {
validUsr = false;
}
}
});
return validUsr;
}
Somehow though the alert is not waiting for the ajax to finish getting it's data. The console.log(returnedData) in the valUsr() function appears in the console after I've dismissed the alert box. Why is this happening? How can I prevent it? Thanks!
Thomas,
You need to cater for the inherent asynchronicity of ajax, in other words you need to wait until a response to the ajax request has arrived before deciding what to do.
jQuery's Deferreds (and promises) allow us to write simple code but Deferreds tend to blow you mind at first, at least very slightly.
There's no unique way in which to use Deferreds for a problem like this but here's one.
$(document).ready(function() {
$('#submit_pw_ch').on('click', function() {
var form = this.form; //the form containing the submit button and the fields .
//`alertArr` is an array to which messages will be added.
var alertArr = ["Please correct the following errors:"];
//`addAlert` will be called from a `Deferred.resolveWith(this, ...)` statement.
//The context, `this`, is unused.
function addAlert(index, txt) {
alertArr[index] = txt;
}
//`compositeAction` will be called from a promise.done() statement.
function compositeAction() {
//first filter out null messages (ie. validation successes) from alertArr.
var message = $.map(alertArr, function(txt, i){
return txt || null;
});
if(message.length > 1) {
//then alert the complete message with line breaks
alert(message.join("\n"));
} else {
//submit the form to change the password
//or another ajax call as required
form.submit();
}
}
// Invoke ajax validators and assign returned promises.
// An index is passed, so the text messages can be displayed in a logical order,
// regardless of the order in which the validation promises are resolved.
//If we didn't care about the order of the messages then the code would be slighly simpler.
var vUsr = valUsr(0),
vPwd = valPwd(1),
sPwd = samePwd(2);
//All validations adopt a similar pattern regardless of whether ajax is involved or not.
//Here, we establish what is to be done when the promise are resolved, or
//what is to be done immediately if the promise are alrady resolved.
vUsr.done(addAlert);
vPwd.done(addAlert);
sPwd.done(addAlert);
//At this stage, `addAlert` will contain entries for successful as well as unsuccessful validations. Successful entries will be filtered out by `compositeAction`
//Establish what is to be done when all three promises are resolved.
$.when(vUsr, vPwd, sPwd).done(compositeAction);
//Return false unconditionally
return false;
});
function valUsr(index) {
var messages = {
validated: '',//important - this message must be an empty string - do not change
notValidated: '- Your current username and password are invalid.',
ajaxError: '- Validation error: username and password.'
};
//Create a Deferred object, which will be resolved in response to several different outcomes.
var def = $.Deferred();
$.ajax({
type: "post",
url: "queries/confirm_user.php?<?=time()?>",
data: {
'un': $('#uNameInput').val(),
'pw': $('#uPwdInput').val()
},
dataType: "json",
success: function (returnedData) {
if (returnedData == 'true') {
def.resolveWith(this, [index, messages.validated]);
} else {
def.resolveWith(this, [index, messages.notValidated]);
}
},
error: function() {
def.resolveWith(this, [index, messages.ajaxError]);
}
});
return def.promise();//Return a promise derived from the as yet unresolved Deferred.
}
function samePwd(index) {
var pw1 = $('#uPwdInput').val();
var pw2 = $('#uPwdInput2').val();
var errMessage = (pw1 === pw2) ? '' : '-The confirmation of your new password does not match the previous entry';
var def = $.Deferred();//Create a Deferred object, which will be resolved immediately
def.resolveWith(this, [index, errMessage]);
return def.promise();//Return a promise derived from the already resolved Deferred.
}
});
valPwd() will be of the same format as either valUsr() or samePwd(), depending on whether ajax is involved or not.
Ajax is run on the fly, synchronously
You will need to check the validation of the other fields after the ajax request has completed in the success callback. You can turn off the synchronous request but the browser will freeze up 'till it gets one, not advised.
You will need to restructure your calls to reflect this; I would suggest that as soon as they have finished typing the password and the field blurs you send the request to check. That way, if there are any errors you will be able to prevent the wait time at the end of the form.

jQuery Dynamic Function and Variable

I am trying to create a function that handles the 'keyup' event for several input fields and passes the input value to a php script. Here's the code I have so far
$(document).ready(function () {
$("#email").keyup(function () {
val = $("input#email").val();
what = 'email';
aFunction(val, what);
});
});
function aFunction(val, what) {
var dataString = what + '=' + val;
var error = "email_check";
$.post("key.php", dataString, function (data) {
//if (data.[error] == 'invalid'){
if (data.email_check == 'invalid') {
$("#ppp").html('error');
} else {
$("#ppp").html('good to go');
}
}, "json");
//return false;
}
When I uncomment
//if (data.[error] == 'invalid'){
and comment out
if (data.email_check == 'invalid'){
My the script doesnt execute and js file doesn't load into the firebug script console - I assume means there's an error because when I undo that and refresh I can view it. I've tried added single and double quotes to the variable. Also, it would be helpful if there was a way to see what the is error is, but I don't know how to do that.
Your primary problem here is that you should use either dot notation ("data.error") or array notation ("data['error']") but not both ("data.['error']").
Javascript does not support braces in identifiers.
If the key is actually just error, you can write if (data.error == 'invalid').
If it is [error], you'll need to write if (data['[error]'] == 'invalid)`.
To see syntax errors, go to Firebug's Console tab.

Categories

Resources