return javascript variable from inside callback function - javascript

I am trying to get client.get to return the reply value so it can be used globally.It keeps saying undefined.any suggestions
var redis = require("redis");
var websocket= require("websocket");
var valuewanted;
websocket.on('message', function(data) {
if (data.type == "purchase" && data.price > 0) {
console.log("==========================================================");
console.log(data );
console.log("==========================================================");
client.get(p1, function(err, reply) {
var valuewanted = reply;
console.log(reply);
});
});
the console.log logs the value but if i try to log valuewanted it doesnt work.

Drop the var within the client.get function:
client.get(p1, function(err, reply) {
// valuewanted already defined above
valuewanted = reply;
console.log(reply);
});
If you use var within a function, it becomes scope-blocked to that function.
From mozilla:
The scope of a variable declared with var is its current execution
context, which is either the enclosing function or, for variables declared outside any function, global.
In this case, using var within that function redefines it within that function, and its scope becomes "the enclosing function". Hope this helps.

Related

Global scoped variable not accessible

Merged with Can't access variable (array) from another function (defined in global scope).
NOTE: this is not an async problem. This question was closed prematurely. I am reposting and answering so the OP has an answer that is useful.
I'd like to use a variable (array) from another function. I already defined it in global scope, but it doesn't work..
Here is my code for better understanding:
var globalData = '';
var data = '';
$.getJSON('https://...' + data[x].id + '.json', function(data) {
globalData = data;
data = globalData.name;
console.log(data); // works just fine
if (condition === 1) {
function2(); // calls this function
} else {
function3();
}
});
function function2() {
console.log(data); // just an empty line
console.log(globalData); // UPDATE: works just fine
}

JS - Calling function from function not working

I have a function that gets called, and in it, I call another function called:
updatePerson(name)
For some reason it never activates when the function below is called. Everything else in the function works.
function updateName(name) {
$.get('XXX',function (data) {
var results = $.parseJSON(data);
var matchName = String(results.data[0].first_name);
updatePerson(matchName);}
);
};
Has anyone got an idea what I am doing wrong?
If I run alert(matchName) I get Nick as a response.
If I run console.log(updateMap(matchAddress)) I get undefined
It could do with the fact that you're passing a parameter from a callback function. In Javascript, variables inside a Callback are not available outside the callback.
Try setting the value of String(results.data[0].first_name) to a variable declared outside of the updateName function (i.e a global variable) and then call the updatePerson function outside of update name, with the globally declared variable as a parameter. Like so
var globalMatchName = '';
function updateName(name) {
$.get('XXX',function (data) {
var results = $.parseJSON(data);
globalMatchName =String(results.data[0].first_name);
}
);
updatePerson(globalMatchName)
}

function returns undefined while log shows result

I want to call a function inside a loop.
This function returns undefined, while the log shows me the correct output in the function.
Where i call the function:
function getAllFilters(allFilters){
var allFiltersWithCount =[]
allFilters.forEach(function(item){
if(item.name != null || typeof(item.name) != 'undefined') {
allFiltersWithCount.push(function (callback){
console.log("inloop" + getFiltersByFilterCategory(item.name) );
callback(null,getFiltersByFilterCategory(item.name));
});
}
});
async.parallel(allFiltersWithCount, function(err, result) {
console.log("results " + result);
return allFiltersWithCount;
});
}
And a part of the function i'm calling:
function getFiltersByFilterCategory(filterCategory){
switch(filterCategory){
case "prescription":
ProductSchema.aggregate(
{
$group:
{_id: '$prescription', total: {$sum:1}}
},
function(err,res){
var toreturn = {name:"prescription",filters: sort(res)};
console.log(toreturn);
return toreturn;
})
case "usage": {...}
in my log I see:
inloopundefined (multiplied by the number of loops)
results ,,,,,
{ name: 'prescription',
filters:
[{...},{...},...]
So I'm guessing it runs this function async. But how does javascript let me do this correctly and what is really happening? Does he returns the function to early, and then just do the console.log afterwards? Or what?
Assuming the getFiltersByFilterCategory function is defined on the window object (defined on the global scope). The undefined is logging because the function is ultimately being called with a context that is not window, so to fix this you can declare the function as a variable within the closure where it's still within scope.
I.e. Below, (obviously a cleaner solution would be restructured.)
function getAllFilters(allFilters){
var allFiltersWithCount =[];
var getFiltersByFilterCategory = function(name){ };
allFilters.forEach(function(item){
if(item.name != null || typeof(item.name) != 'undefined') {
allFiltersWithCount.push(function(callback){
console.log("inloop" + getFiltersByFilterCategory(item.name));
callback(null,getFiltersByFilterCategory(item.name));
});
}
});

How to add extra parameters to a function callback

I am using a few callbacks in an app that I'm writing. I am using Mongoose models and need to save a few different places. The save function takes a callback, and the callback gets error and model for its parameters, but I'd like to send the callback an extra parameter that the function needs. I'm not sure of the proper syntax to be able to do this. Below is some example code of what I'm going for...
var saveCallBack = function(err, model, email_address){
if(err) {
//handle error
}
else {
//use the third parameter, email_address, to do something useful
}
};
Below, token is a mongoose model. As I said, save takes a callback and gets passed error and model, but I'd like to also send my callback a variable email_address that I figure out at some other point. Obviously the appendParameter function is pseudo-code, but this is the type of functionality that I need.
token.save(saveCallBack.appendParameter(email_address));
If you make that the first parameter instead, you can use .bind().
token.save(saveCallBack.bind(null, email_address));
var saveCallBack = function(email_address, err, model){};
I'm using bind function for appending additional parameters for callbackes
var customBind = function (fn, scope, args, appendArgs) {
if (arguments.length === 2) {
return function () {
return fn.apply(scope, arguments);
};
}
var method = fn,
slice = Array.prototype.slice;
return function () {
var callArgs = args || arguments;
if (appendArgs === true) {
callArgs = slice.call(arguments, 0);
callArgs = callArgs.concat(args);
} else if (typeof appendArgs == 'number') {
callArgs = slice.call(arguments, 0);
}
return method.apply(scope || window, callArgs);
};
}
This customBind function accepts four arguments, first one is original callback function, second is the scope, third is additional parameters (array), and fourth is flag append or replace. If you set last parameter to false than only parameters in array will be available in this function.
and with this function you can simple add new parameters or to override the existing one
var callback = customBind(saveCallBack, this, [array_of_additional_params], true)
in this way all original parameters remain and your parameter will be appended to the end.
No matter how many parameter you defined, the callee will always pass the same parameter inside its process.
but it will be more simple, just use a variable that is visible from outside of the callback.
Eg:
var email = 'yourmail#mail.com';
var saveCallBack = function(err, model){
if(err) {
//handle error
}
else {
alert(email);
}
};
Updated (#Jason): then you can use Immediately-Invoked Function Expression (IIFE)
(function(mail){
var saveCallBack = function(err, model){
if(err) {
//handle error
}
else {
alert(mail);
}
};
token.save(saveCallBack);
}, emailAddress);

Globally defined variable not being found

I have declared a global variable, var linkArray=[], but it is not being picked up inside of a phantomJS function. The error message is: phantom stdout: ReferenceError: Can't find variable: linkArray. How can I make this be found? I've tried declaring it with window.linkArray, but since this is a headless application, I then get a different error, ReferenceError: window is not defined.
Thus, I need a way to make var linkArray=[] global.
var phantom = require('phantom');
var linkArray=[];
phantom.create(function (ph) {
ph.createPage(function (page) {
var main_file="file:///C:/whatever/index.html";
page.open(main_file, function (status) {
console.log("opened " + main_file +"\n",status+"\n");
page.evaluate(function () {
for (var i=0; i < document.getElementsByTagName('a').length; i++) {
linkArray.push(document.getElementsByTagName('a')[i].href)
}
return linkArray;
}
, function (result) {
console.log(result)
ph.exit();
});
});
});
}, {
dnodeOpts: {
weak: false
}
});
PhantomJS has a page context and outer context. The page context is sandboxed, so you need to explicitly pass the variable into it. It is passed by value. The docs say:
Evaluates the given function in the context of the web page. The execution is sandboxed, the web page has no access to the phantom object and it can't probe its own setting.
But also note the note.
Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.
Closures, functions, DOM nodes, etc. will not work!
To solve this, the outer variable has to be passed into the page context (evaluate) and returned
page.evaluate(function(linkArray) {
// page context, linkArray is a local variable now
for (var i=0; i < document.getElementsByTagName('a').length; i++) {
linkArray.push(document.getElementsByTagName('a')[i].href)
}
return linkArray;
}, function finished(result) {
// outer context
console.log(result)
linkArray = result;
ph.exit();
}, linkArray); // pass values for the page context as last parameters

Categories