I have a recursive JSON crawler function that looks for a specified function then returns it. However, it is returning undefined and I am not sure why.
Here is the script:
function get(what, where){
where = typeof(where) != 'undefined' ? where : user.object;
for(entry in where){
if(typeof(where[entry]) =="string"){
if (entry == what) {
result = where[entry];
console.log(result)
return result;
}
}else if(typeof(where[entry]) =="object"){
get(what, where[entry]);
}
}
}
the console.log returns correctly but the return statement below it fails.
It's because you're not returning your recursive branch of the code, this:
get(what, where[entry]);
should be:
return get(what, where[entry]);
So on that branch, though you're executing all the way down, you're not returning the result back up, so you get the default return: undefined.
If you dont write a return-statement in a JavaScript function, but it reaches its end anyway, then it returns undefined. That is (probably) what has happened here, since if you dont enter the if-statement with the return-statement, you will not get to return anything.
EDIT:
As a rule of thumb, you should ALWAYS return something in every bransch of your code. A static language compiler would have warned you about this, but here you have to make sure yourself.
Example:
function get(what, where){
where = typeof(where) != 'undefined' ? where : user.object;
for(entry in where){
if(typeof(where[entry]) =="string"){
if (entry == what) {
result = where[entry];
console.log(result)
return result;
}
}else if(typeof(where[entry]) =="object"){
get(what, where[entry]);
// Are you sure you don't want to return anything here?.. hm...
}
}
// Here be dragons! What will be returned from the function?
// Hint: Undefined! :)
}
Both those places could probably use return statements. The last one need one because what if the for-loop doesn't have any entries to enumerate over?
You probably want to modify the code:
get(what, where[entry]);
to
return get(what, where[entry]);
:-P
Related
I have a little helper function that is not evaluating on either the If or Else.
I know the function is being called because I have the nlapiLogExecution, which is how you debug in NetSuite. Notes on what is being logged are with the code.
How is this possible? I have tried to use == operator as well. I also tried to set it as a variable inside the function (which I don't think is necessary).
function convertUnit(unit, cubicMeters){
nlapiLogExecution('DEBUG','convertUnitFunction',typeof(unit))
// typeof is String
nlapiLogExecution('DEBUG','convertUnitFunction',unit)
// value is Each
if (unit === 'Each'){
return cubicMeters
nlapiLogExecution('DEBUG','equals Each', cubicMeters)
// does not log here
}
else {
nlapiLogExecution('DEBUG','else statements', 'equals else')
// Does not log here
}
}
You are entering the if statement, but the function returns before you can log anything. Try switching the order of the return and log statements:
function convertUnit(unit, cubicMeters){
nlapiLogExecution('DEBUG','convertUnitFunction',typeof(unit))
// typeof is String
nlapiLogExecution('DEBUG','convertUnitFunction',unit)
// value is Each
if (unit === 'Each'){
nlapiLogExecution('DEBUG','equals Each', cubicMeters)
// will log something now if you pass 'Each'
return cubicMeters
}
else {
nlapiLogExecution('DEBUG','else statements', 'equals else')
// will log something if the else branch is taken
}
}
You are returning before it gets to the nlapiLogExecution in the 'Each' section. Not sure why it isn't running on the else though, unless you are only passing 'Each'
I have created a prototype method that return true and false. The problem is that it doesn't return the value. I know it reaches the statement because I have used console.log() when the condition is met but doesn't return the value.
I cant seem to figure this out. If anyone can help me out here I would really appreciate it. Below is my code
function Validation(){
this.checkRequired = function(){
$(".modifiers-group-cont").each(function(){
var select_opt_notify = $(this).find(".select-option-notify");
/*The radio buttons that are required are always going to be marked check,thats why we are only
* checking for the checkbox*/
if($(this).attr("data-is-checked") == "false" && $(this).attr("data-input-type") == "checkbox"){
select_opt_notify.show();
return false;
} else {
select_opt_notify.hide();
return "true";
}
});
}
function ModifierPost(){
(function(){
$("#add-to-cart").click(function(){
console.log(validation.constructor); //Shows undefined
if(validation.checkRequired()){
$.post("#",$("form").serialize()+ "&item_id=" + item_id);
}
});
})();
}
The return statements belong to the function in each:
$(".modifiers-group-cont").each(function(){
You'll need to expose the values you'd like to return to the outer scope and call return after the call to each.
You have created your function with Capital V and calling with Smaill v in the validation function name
That is the reason it is giving you undefined the place you have mentioned in your code.
console.log(validation.constructor); //Shows undefined
if(validation.checkRequired()){
it should be with Capital V like
console.log(Validation.constructor); //Shows undefined
if(Validation.checkRequired()){
I am trying to check if a value is present inside an array of object
function hasProperties(id){
jQuery(JSON.parse(jQuery("#PropertiesField").html())).each(function () {
if(id== jQuery(this)[0].properties.id) {
console.log((id== jQuery(this)[0].properties.id));
return "Present";
}
})
};
var something = hasProperties("someid");
the above snippet returns undefined for something, but also true is logged in console. why is it not returning present when condition satisfies, what is the mistake that I have done?
The function provided in the each method is an anonymous inner function. Therefore, nothing is returned outside of each() context. To tackle this you can do something like,
function getProperty(id){
var result;
$('your element').each(function(){
//If your condition is true
result=expectedValue
});
return result;
}
I don't think you actually want to parse #PropertyField html as JSON and then want to make its jQuery object. Do a check on it.
Instead of doing jQuery(this)[0].properties.id, just do this.id, that is not a right syntax.
I found the issue, the return i had is for the .each(). I added a return outside the foreach function and it works now
function hasProperties(id){
var found =false;
jQuery(JSON.parse(jQuery("#PropertiesField").html())).each(function () {
if(id== jQuery(this)[0].properties.id) {
console.log((id== jQuery(this)[0].properties.id));
found= true;
return;
}
})
return found;
};
var something = hasProperties("someid");
I am trying to return whether a user already exists in a MongoDB. Running console.log within collection.find() prints the correct amount (greater than 0). However, when userExists is called, it always returns false (0).
How do I make Javascript wait for these functions to complete before returning a value? I've read about jQuery's $.Deffered(), but this feels dirty to me, and it didn't work.
function userExists(db, uid){
var collection = db.get('users');
var ret = 0;
collection.find({"uid":uid},{},function(e,docs){
ret = docs.length
});
return ret > 0?true:false;
}
As some have noted, collection.find is asynchronous, so when you reach the next line in userExists (the line where you've got return ret > 0?true:false;), it's too early and the value of ret hasn't been set. Anywhere outside of the callback to collection.find (and any functions it calls in turn), the query hasn't happened yet.
There is (basically) no way to "pause" userExists until after the query, so you need to change your whole approach. What you need is the Continuation Pattern. This means that whatever you're doing with the result of collection.find has to happen in the callback.
I don't know what you're trying to do with ret, so this might mean big changes to how your code is organized. Here's an outline that I hope will give you the general idea:
function processResultAndDisplayToTheUser(ret) {
//everything that needs to happen after the value of ret is set
if (ret > 0) {
doSomething();
} else {
doSomethingElse();
}
}
function userExists(db, uid){
var collection = db.get('users');
//ret doesn't exist here
collection.find({"uid":uid}, {}, function(e,docs){
var ret = docs.length;
//ret finally exists, so pass it to a function and use it
processResultAndDisplayToTheUser(ret);
});
//ret doesn't exist here either
}
//ret still doesn't exist here
I took the hint and ended up restructuring my code. I created a function addUpdateUser(), did the count there, then ran the addUser() or updateUser() functions accordingly.
addUpdateUser(db, {
"uid" : uid,
});
function addUpdateUser(db, userInfo){
var collection = db.get('users');
collection.find({"uid":userInfo.uid},{},function(e,docs){
if(docs.length > 0){
updateUser(db, userInfo)
}else{
addUser(db, userInfo)
}
});
}
since collection.find is asynchronous method that doesn't return immediately you need to change your code to,
you can pass a callback function
function userExists(db, uid,callback){
var collection = db.get('users');
collection.find({"uid":uid},{},function(e,docs){
callback(docs.length);
});
}
now you can call this userExists function as
userExists(db, uid,function(ret){
//do something here
})
I want to use return false to break a .each() but also return a value at the same time. How can I do this?
Please refer to a work-around function to see what I am trying to do:
function HasStores(state) {
var statehasstores = false;
$(stores).each(function (index, store) {
if (state == store.state && store.category == "meyers") {
statehasstores = true;
return false; // break
}
});
return statehasstores;
}
What Id like to do in pseudo code is:
Function () {
for() {
if found {
return true;
}
}
return false;
}
You're doing it right...
Quote from http://api.jquery.com/each/
"We can stop the loop from within the callback function by returning false."
Be creative:
try {
$(stores).each(function (index, store) {
if(state == store.state && store.category == "meyers"){
throw store;
}
});
}
catch(e) {
// you got e with the value
}
No, I was just kidding, don't use this :). It came as an idea I liked to share.
Use a variable outside the loop to get the value and use it afterward.
var value;
$(stores).each(function (index, store) {
if(state == store.state && store.category == "meyers"){
statehasstores = true;
value = store; // added line
return false; //break
}
});
alert(value);
The way you're doing is just fine. I've tested on jsFiddle, see an example here.
It's not working for you? Can you show more context?
jQuery .each
Alternatively, you could use a for loop instead of each(), and just return the value.
What you're suggesting is the way to do it. I'd think of it less as a workaround and more as an idiom.
How about:
$.each( myObj, function( key, value ){
...
if( sthg... ){
myObj.somethingWentHorriblyWrong = true;
return false;
}
});
if( myObj.somethingWentHorriblyWrong ){
// ... do something, not forgetting to go:
delete myObj.somethingWentHorriblyWrong;
}
PS I was initially interested in what $.each(... actually returns. As it says on the relevant JQ page, "The method returns its first argument, the object that was iterated", but in fact the solution doesn't even require that you use that fact...
PPS Need a function that returns a value? Wrap in an outer function of course.
Okay I guess there's a little doubt about this point so maybe I'm making it clearer here :
When jquery doc says : "We can stop the loop from within the callback function by returning false." and you do :
Function () {
for() {
if found {
return true;
}
}
return false;
}
This doesn't mean that you're function will return true when find the searched element. Instead, it will always return false.
So to make your function work as you whish I propose to do so :
Function () {
variable found = false;
foreach() {
if found {
found = true;
return false; // This statement doesn't make your function return false but just cut the loop
}
}
return found;
}
Of course there are many other ways to perform this but I think this is the simplest one.
Coopa - Easy !
As others have noted from jQuery Each, returning false will only break from the loop not return the value, returning true however will 'continue' and immediately begin the next iteration. With that knowledge, you could somewhat simplify your code like this:
function HasStores(state) {
var statehasstores = false;
$(stores).each(function (index, store){
// continue or break;
statehasstores = !(state == store.state && store.category == "meyers"))
return statehasstores;
});
return !statehasstores;
}
This of course is a little silly using the double negative, and has the side effect of saving 'true' to statehasstores for every false iteration and vice versa, however the end result should be the same and you no longer have that if statement.