I have an input field, where a user can enter an INPUTVALUE, this INPUTVALUE gets checked for correctness against a reg-ex, then sent off to a php file, which will do calculations with it, and return either 0 (meaning the INPUTVALUE was not valid) or a RETURNVALUE. This RETURNVALUE should be displayed in an element on the website with the id #VALUEINFO. Also I would like this RETURNVALUE returned by my function get_value_by_input(). In order to check what was returned, I am displaying an alert first.
(A practical application for this could be for example a coupon code on an order... put in your coupon code, we check it in the database, it returns the value of the coupon or 0 if it was not a valid coupon code.)
My problem is, I must be messing up something with the variable scope in Javascript, because eventhough my #VALUEINFO displays the correct RETURNVALUE, the alert will always say no returnvalue specified.
function get_value_by_input()
{
var returnvalue;
var valueinfo = $('#valueinfo');
valueinfo.text('');
var inputvalue = $("input[name='inputvalue']").val();
var correctinput = /^[a-zA-Z]*$/i;
if( inputvalue.length > 0 && correctinput.test(inputvalue))
{
$.post('ajax/valuecheck.php', {inputvalue_test: inputvalue}, function(is_valid){
if(is_valid == 0)
{
valueinfo.text('Sorry, this input is not working...');
returnvalue = 0;
}
if(is_valid != 0)
{
valueinfo.text('the returned value for your input is '+is_valid);
returnvalue = is_valid;
}
});
}
else
{
if(inputvalue)
{
valueinfo.text('Invalid input.');
returnvalue = 0;
}
}
if(returnvalue)
{
alert('the value for this input was was '+returnvalue);
return returnvalue;
}
else
{
alert('no returnvalue specified.');
return 0;
}
}
Again:
Why does this code ALWAYS alert 'no returnvalue specified' eventhough #VALUEINFO gives me the correct returnvalue?
I assume this has to do with the if block, I read that javascript will not ignore the setting of any variables within if blocks, even if the condition is not fulfilled... But how else could I pass the value to #valueinfo and return it at the same time?
Any help or suggestions would be greatly appreciated! :-)
EDIT:
Well, yes it has nothing to do with variable scope, but it's about Asynchronus-jax.
I ended up restructuring my code... get_value_by_input() is now more of a process_input() function. First the INPUTVALUE is checked for correctness, and only if there were no errors $.post(... is called. The value returned by the php file is then used immediately within the callback function, rather then to be returned and then used from another function... Unfortunately I couldn't get my brain wrapped around working with .done() or something similar, guess I've been working too long on this today already... -.- Maybe next time. It works for now :)
As mentioned in the comments, you need to handle the return value in a callback (since you're dealing with an asynchronous call).
This might give you a better understanding on how to solve the problem:
function getReturnValue(inputvalue, callback){
$.post('ajax/valuecheck.php', { 'inputvalue_test': inputvalue}, callback);
}
var inputvalue = $("input[name='inputvalue']").val();
getReturnValue(inputvalue, function(is_valid){
//handle is_valid here
//it's the data returned from the ajax call
});
There are a lot of similar threads.
Related
Here is a link to my JS fiddle: https://jsfiddle.net/apasric4/v1qkmgyu/1/
function inputCheck(input) {
if (input.name==="email") {
console.log("email")
return isValidEmail
} else if (input.name==="password") {
return isValidPassword
console.log("pass")
} else if (input.name==="userName") {
return isValidUserName
console.log("user")
}
}
function isValidEmail (email) {
return /^[^#]+[#][^#.]+\.[a-z]+$/.test(email)
}
function isValidPassword(pass) {
return /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/.test(pass)
}
function isValidUserName(user) {
return /^[a-zA-Z0-9]+([_ -]?[a-zA-Z0-9])*$/.test(user)
}
function validation(e) {
e.preventDefault()
inputs.forEach(input=> createListener(inputCheck(input)))
}
function createListener(validator) {
return (e)=> {
const inputValue=e.target.value;
const valid=validator(inputValue)
console.log(valid)
}
}
I'm trying to create form validation using closures. I am trying to make my code as efficient as possible.
I want to loop over each input element (without selecting each individually), and apply an event listener to each one. The inputCheck function would return a validator function depending on the name attribute of each input, and the createListener function takes the value returned by inputCheck, which would be a specific type of validator, and then for testing purposes, console.log true or false.
So far, the only if branch that works in the inputCheck function is the first one associated with name attribute email. The other if branches won't work if I type values into other input elements and submit the form.
Can anyone tell me where I'm going wrong and how to improve my code?
I'm new to closures so I understand that this issue might seem relatively simple to most of you.
I can observe two things:
First, just like #VLAZ pointed out, two console.log in inputCheck are actually not executed since they are placed after return.
Second, createListener and validation are not quite right. createListener returns a function with one argument. validation forEach doesn't log anything because createListener returns a function, no function execution here.
There is another problem with the argument e of createListener. It seems like you treat it as an event, but based on your implementation, there is only one event, that is form submit event. So, I'd suggest to modify these two functions a little bit:
function validation(e) {
e.preventDefault()
inputs.forEach(input=> createListener(inputCheck(input))(input))
}
function createListener(validator) {
return (e)=> {
const inputValue=e.value;
const valid=validator(inputValue)
console.log(valid)
}
}
Then, the console prints out true or false based on the input value of each input field.
Please check whether the output is your intension or not https://jsfiddle.net/jqgbefhw/
So I really couldn't find much on this. The idea is that I have a user input (text) and I want to check if its valid code in JS and then run it if it is.
I know that I can do if (typeof userInput === "function") { if the userInput was actually a function, but the user input is just a string input at this point, so I'm quite stuck, and it also contains any arguments or other code.
As an example, the input may be "alert('test')" and that would be valid, and I would like to run that, however something like "madeUpFunction(lol)" would be invalid.
I'm happy if I can just get functions working and not any JS code.
You can extract the string up until the first ( in order to get the function name, and then test that it exists using typeof eval(funcName). Then use the Function constructor to make sure that the syntax is valid for the rest of the arguments without actually executing the code.
You can then return the function which executes what the user entered, but note that there may be security issues if you decide to execute the function.
function parseFunctionCall(str) {
var funcName = str.slice(0, str.indexOf('('));
if (typeof eval(funcName) === 'function') {
return new Function(str);
} else {
throw new Error('Invalid function name');
}
}
console.log(parseFunctionCall("console.log('hi')"));
You can use eval("typeof "+ input) to achieve what you want. The argument of the eval() function is a string. If the string represents an expression, eval() evaluates the expression.
var myFunc = function(){};
var input = prompt('Enter input string');
if(eval("typeof "+input) === "function"){
document.getElementById('d1').innerHTML = "Yes it's a funtion";
}
else{
document.getElementById('d1').innerHTML = "Not a funtion";
}
<div id="d1">
</div>
Assuming this is in a browser and that that function you want to check is in the global scope:
if (typeof window[userInput] === "function" ) {
...
}
Say I have a function name myFunA, when the first time call the function and pass a parameter to it, the function actually stored the variable. Each time I call this function, it will return the same variable, until I call the function again and pass a parameter to replace the previous parameter.
function myFunA(input){
if(input exist){
storedVar = input //declare a variable and store the input
}
console.log(storedVar);
}
myFunA('First Input'); // output will be 'First Input'.
myFunA(); // output will still be 'First Input'.
myFunA('Second Input'); // output will be 'Second Input'.
myFunA(); // As the variable is replaced, the output will still be 'Second Input'.
Is this possible?
I know that there is a Garbage Collection feature in JavaScript to scrap the variable and release memory, but is there anyway to prevent?
Really appreciate if someone could let me know the way. If this is not possible to achieve, it is still good to confirm it.
Thank you so much.
Javascript functions are first class objects. Therefore, you can set a property of the function just like any other variable.
function myFunA(input) {
if (input) {
myFunA.storedVar = input;
}
console.log(myFunA.storedVar);
}
myFunA('First Input'); // First Input
myFunA(); // First Input
myFunA('Second Input'); // Second Input
myFunA(); // Second Input
The answer of #NinaScholz is fine, but allows you to change the stored value without calling the function. If you want to avoid it, here is another pattern :
var myFunA = (function() {
var storedVar = null;
return function(input) {
if(typeof(input) != "undefined") {
storedVar = input;
}
console.log(storedVar);
};
})();
My apologies for the one millionth iteration of this type of question. I've already seen a number of other posts talking about this, and I still can't wrap my head around being able to invoke a function after the callback is successful and returns. I must have read this post over half a dozen times:
How do I return the response from an asynchronous call?
The Code
Anyway .., my question I hope anyone could shed some light on. I have a custom jQuery validator method that checks if a username is available.
jQuery.validator.addMethod("usernameAvailability",
function(value, element) {
console.log('starting usernameAvailability');
if(this.optional(element) === true){return true;}
else{
console.log('ending usernameAvailability, about to return get_availability');
return availabilityCheck.get_availability('username');
}
}, "Username already in use." );
The custom jQuery validator method calls get_availability(element) in namespace availabilityCheck.
var availabilityCheck = (function() {
var usernameIsAvailable, emailIsAvailable, Callback, AJAX_Availability_Check, change_Availability;
usernameIsAvailable = null;
emailIsAvailable = null;
AJAX_Availability_Check = function(callback, element){
console.log('starting AJAX_Availability_Check');
if(element==="username"){
selection = {username:$('#id_username').val()};
}
else{
selection = {email:$('#id_email').val()};
}
$.ajax({
url: '/register/',
type: 'get',
data: selection,
dataType:'text',
async: true
}).done(Callback(element));
};
change_Availability = function(element, bool) {
if(element === 'username'){
usernameIsAvailable = bool;
}
else{
emailIsAvailable = bool;
}
};
Callback = function(element) {
return function(result, textStatus){
bool = result === "True" ? true: false;
change_Availability(element, bool);
return usernameIsAvailable;
};
};
return{
get_availability: function(element){
AJAX_Availability_Check(Callback, element);
return element === 'username' ? usernameIsAvailable : emailIsAvailable;
}
}
})();
The Problem and My Question
My problem The input correctly validates whether the username is already in use, but the user needs to trigger validation twice since get_availability returns before the Callback can change usernameIsAvailable to the proper boolean.
My Question How do I restructure my code so my custom jQuery validate method is invoked by the callback? Or how do I ensure that it won't validate until the Callback returns?
The problem is your structure... I don't know where you got that from but throw it away and burn it, then forget you ever saw it.
You can simplify your code to look like this:
var availabilityCheck = function() {
var usernameIsAvailable = null, emailIsAvailable = null,
AJAXAvailabilityCheck, changeAvailability;
AJAXAvailabilityCheck = function(element){
console.log('starting AJAX_Availability_Check');
if(element==="username"){
selection = {username:$('#id_username').val()};
}
else{
selection = {email:$('#id_email').val()};
}
$.ajax({
url: '/register/',
type: 'get',
data: selection,
dataType:'text',
async: true
}).done(changeAvailability(element));
};
changeAvailability = function(element, theBool) {
if(element === 'username'){
usernameIsAvailable = theBool;
}
else{
emailIsAvailable = theBool;
}
};
this.getAvailability = function(element) {
AJAXAvailabilityCheck(element);
return element === 'username' ? usernameIsAvailable : emailIsAvailable;
}
};
So your callback is now actually something useful instead of just another useless layer.
However as I point out below, your result wasn't ever actually defined as far as I could tell so your going to have to figure out what theBool should be.
Some things of note:
Callback = function(element) {
return function(result, textStatus){
bool = result === "True" ? true: false;
change_Availability(element, bool);
return usernameIsAvailable;
};
};
You return an anonymous function for no particular reason, and your result variable isn't defined... at least with the code as you have it, so with what you have it's always resolving to false. Also if your just checking for truthyness then you don't need a tuple you can just do result === "True" which will evaluate to true or false, no need for the extra ? true : false.
Also, don't use words like bool for variable names. Bool is a type of variable and is a reserved word. Javascript lets you use it cause... Javascript will let you do just about anything, but its bad practice.
Finally you mixed like 10 different types of casing. Now casing is a personal preference (I personally prefer underscores to camelCase, which is the javascript convention), but no matter what case you use. USE ONLY ONE CASE!
Now I believe your real issue here is that you don't understand what a self-invoking function is for.
You use this syntax: var availabilityCheck = (function(){})(); which creates a self-invoking function; which means that it's going to fire without being called! Which means all this does is call your ajax and cause an extraneous server hit when your user hasn't even entered any data yet.
I believe that you did it so you could use this syntax availabilityCheck.getAvailability() in your invoking function, but the better way to do that is to do what I did above and make getAvailability a property of availabilityCheck by using the this keyword. Then you can use the same syntax without running your whole function twice.
You should almost NEVER (there are always exceptions of course) put an ajax call in a self invoking function. If the call doesn't depend on user input, then you should of just loaded the data when your page was requested the first time.
I am performing two validations on the client side on the samve event.
I have defined my validations as shown below
btnSearch.Attributes["OnClick"] = "javascript:return prepareSave(); return prepareSearch();"
Pseudo code for
prepareSave():
{
if (bPendingchanges)
{
return confirm('Need to save pending changes first, click OK and loose changes or cancel to save them first')
}
else
{return true}
}
Pseudo code for
prepareSearch():
{
if (bNoSearchText)
{
alert('Please specify search criteria before proceeding')
return false;
}
else
{return true;}
}
When bPendingchanges=false, I never get the second validation running.
Anyone who can quickly spot what I have overlooked here? Please?
return, as the name implies, returns control back to whatever called the code in question. Therefore, anything that's after a return statement
return prepareSave(); return prepareSearch();
// ^^^^^^^^^^^^^^^^^^^^^^^ e.g. this part
never executes. Try return (prepareSave() && prepareSearch());
Your second return statement will never be reached. Execution stops after javascript:return prepareSave().
Looks like you want to return true if both functions return true - therefore, do:
btnSearch.Attributes["OnClick"] = javascript: return prepareSave() && prepareSearch();
That's because the return prevents the second validation from running. Try this
btnSearch.Attributes["OnClick"] = "javascript:return prepareSave() && prepareSearch();"
"javascript:return prepareSave(); return prepareSearch();"
1) You shouldn't have the "javascript:"
2) return prepareSearch(); will never be executed, because "return prepareSave(); exits your event handler
Try "return (prepareSave() && prepareSearch());"