How to access the values of local variables globally [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I returned the rsltCallback function , when i call the googleSearchSuggestions function , i am getting undefined. When i console.log the input parameter inside the rsltCallback function it's printing the output to console.
var googleSearchSuggestions = function(search_Keyword , element) {
var parsed;
var uri = 'http://suggestqueries.google.com/complete/search?output=toolbar&hl=en&q=' + search_Keyword;
var xhr = (typeof XMLHttpRequest !== 'undefined') ? new XMLHttpRequest() : new ActiveXObject(Microsoft.XMLHTTP);
xhr.onreadystatechange = function(){
xhr.responseType = 'xml';
if(xhr.status == 200 && xhr.readyState == 4)
{
var response = xhr.responseXML;
var items = response.getElementsByTagName('toplevel')
for (var i = 0 ; i < items[0].childNodes.length;i++)
{
parsed = items[0].childNodes[i].firstElementChild.getAttribute('data');
rsltcallBack(parsed);
}
}
};
xhr.open('GET', decodeURI(uri), true);
xhr.send();
var rsltcallBack = function(input){
return input;
};
return rsltCallBack();
};

Because you have an asynchronous function call in your method you need to return the parsedValue at a later time. A way to do this are so called promises.
If you want that variable to be globally accessible then you can just add it to window (eg. window.parsedOutput = ...).

This incident as JavaScript Variable hosting issue. for ex:
var value = "a";
function test() {
var value;
alert(value)
}
test();
the global variable return undefined error. same code as works fine as below
var value = 10;
function test() {
var value ="b";
alert(value);
}
test();
online reference :
http://techslides.com/understanding-javascript-closures-and-scope
http://stackoverflow.com/questions/9085839/surprised-that-global-variable-has-undefined-value-in-javascript

An onreadystatechange function is only called after the state has been changed. This is not immediate; there is a split second in which the state has not yet changed. So you cannot access parsedOutput until the onreadystatechange function is called; its value has not yet been set. JavaScript doesn't just stop and wait for this to happen; it allows the request to be made in the background. It continues executing your code, even though the onreadystatechange method has not yet been called.
To solve your problem, simply wait for a response before using parsedOutput. You do this by using the onreadystatechange function to trigger the next step in your code.
BTW, performing a request in the background like this is call an asynchronous request. It is how you make remote requests with JavaScript; it prevents the script from hanging while waiting for a response.

Instead of accessing local variable, just initialize the variable outside the function and assign values locally,
Copy-Paste this,
var parsed ="";
var googleSearchSuggestions = function(search_Keyword , element) {
var uri = 'http://suggestqueries.google.com/complete/search?output=toolbar&hl=en&q=' + search_Keyword;
var xhr = (typeof XMLHttpRequest !== 'undefined') ? new XMLHttpRequest() : new ActiveXObject(Microsoft.XMLHTTP);
xhr.onreadystatechange = function(){
xhr.responseType = 'xml';
xhr.open('GET', decodeURI(uri), true);
xhr.send();
if(xhr.status == 200 && xhr.readyState == 4)
{
var response = xhr.responseXML;
var items = response.getElementsByTagName('toplevel')
for (var i = 0 ; i < items[0].childNodes.length;i++)
{
parsed = items[0].childNodes[i].firstElementChild.getAttribute('data');
rsltcallBack(parsed);
}
}
}
};
function rsltcallBack(input)
{
setTimeout(function()
{
alert(input);
},2000);
}

There are a few ways to declare global variables
var carName;
function myFunction() {
carName = 'Volvo';
}
This example declares the variable outside of the function and then assigns a value to it inside the function scope.
The other is
function myFunction() {
window.carName = 'Volvo';
}
This sets the variable on the window which can be deleted using delete window.carName.

Related

Returning values from the event onreadystatechange in AJAX [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I am trying to assign a value to the variable val in the code below:
var cmdValue = "/cmd/fetch?x=";
var val;
var returned_data;
function what(){
val = update('#TAG#');
}
function update(tag) {
var req1 = newXMLHttpRequest();
req1.open("GET",cmdValue + tag, true);
req1.send("");
return req1.onreadystatechange= function () {
if (req1.readyState == 4 && req1.status == 200) {
returned_data = req1.responseText;
return returned_data;
}else{
}
};
}
I was tracking the variables in Firebug and it turns out that val gets assigned the function. Is there a way to get the code to run through and then assign the value to the variable val?
In asynchronous programming you do not return data because you don't know when that data is going to become available - it's asynchronous.
The way to do asynchronous programming is using events and/or callbacks.
Example:
var cmdValue = "/cmd/fetch?x=";
var val;
var returned_data;
var performSomeAction = function(returned_data) {
val = returned_data;
}
function what(){
update('#TAG#', performSomeAction);
}
function update(tag, callback) {
var req1 = new XMLHttpRequest();
req1.open("GET", cmdValue + tag, true);
req1.send("");
req1.onreadystatechange= function () {
if (req1.readyState == 4 && req1.status == 200) {
returned_data = req1.responseText;
//fire your callback function
callback.apply(this,[returned_data]);
} else {
}
};
}
This question is one of the most commonly asked questions on SO, at least when it comes to the javascript tag - please search for similar questions before asking your own.
// should have a space after new or was did u notice it
var req1 = new XMLHttpRequest();

XMLHttpRequest prototype of onreadystatechange not called

I'm trying to detect when any ajax call finishes in my UIWebView. I modified the code in this answer: JavaScript detect an AJAX event to the best of my abilities. Here is my attempt:
var s_ajaxListener = new Object();
s_ajaxListener.tempOnReadyStateChange = XMLHttpRequest.prototype.onreadystatechange;
s_ajaxListener.callback = function () {
window.location='ajaxHandler://' + this.url;
};
XMLHttpRequest.prototype.onreadystatechange = function() {
alert("onreadystatechange called");
s_ajaxListener.tempOnReadyStateChange.apply(this, arguments);
if(s_ajaxListener.readyState == 4 && s_ajaxListener.status == 200) {
s_ajaxListener.callback();
}
}
I'm injecting this into the webView but the alert is never firing. If I place an alert at the beginning or end of the script, it'll fire so I'm fairly certain there are no syntax errors.
I'm not a JS guy so I'm hoping this is a trivial problem.
Putting a generic onreadystatechange in XMLHttpRequest.prototype didn't work for me. However the code you linked to can be easily adapted to invoke a custom function whenever that event occurs:
var s_ajaxListener = {};
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;
// callback will be invoked on readystatechange
s_ajaxListener.callback = function () {
// "this" will be the XHR object
// it will contain status and readystate
console.log(this);
}
XMLHttpRequest.prototype.open = function(a,b) {
if (!a) var a='';
if (!b) var b='';
s_ajaxListener.tempOpen.apply(this, arguments);
s_ajaxListener.method = a;
s_ajaxListener.url = b;
if (a.toLowerCase() == 'get') {
s_ajaxListener.data = b.split('?');
s_ajaxListener.data = s_ajaxListener.data[1];
}
}
XMLHttpRequest.prototype.send = function(a,b) {
if (!a) var a='';
if (!b) var b='';
s_ajaxListener.tempSend.apply(this, arguments);
if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a;
// assigning callback to onreadystatechange
// instead of calling directly
this.onreadystatechange = s_ajaxListener.callback;
}
http://jsfiddle.net/s6xqu/

Closure for static values in Javascript

I have a question. We all know the power of closures in Javascript and I want to use this power. Lets say I have a an object named "BRB". WHat I wanted to is whenever user calls the method getBrowser() for the very first time it will find out browser version/name whatever and return it and also store it inside itself as static when getBrowser() called second time it should return the same value without calculation since it is already statically stored somewhere. This can be done in many different ways, we can just store a property in the object and in the first call we can set some values for it and use it later, we can run getBrowser method directly when object is created in the syntax as
(function()(
...
))()
However, this is not what I want. All I want is getBrowser() method to calculate the value only once and use it all the time, I dont want to store the value inside the object somewhere else and I dont want to run this method right away when object is created, I'm allowed to use only and only this method and all action must take place in this one method. I put here an example, as you see it will always print out "0" but what I want is it prints 0,1,2,3 for each console.log request. I hope I made myself clear. Thanks.
(
function(window){
if(window.BRB) return;
var BRB = function(){}
BRB.prototype.getBrowser = function(){
var browser = null;
return function(){
if(browser === null){
browser = 0;
}
return browser++;
}
}
window.BRB = new BRB();
})(window);
console.log(BRB.getBrowser()());
console.log(BRB.getBrowser()());
console.log(BRB.getBrowser()());
console.log(BRB.getBrowser()());
Your requirements are kinda strange. Is this what you're looking for? It works by creating a property on the getBrowser function itself:
(function(window){
if(window.BRB) return;
var BRB = function(){}
BRB.prototype.getBrowser = function(){
if(typeof this.getBrowser.browser == "undefined"){
return this.getBrowser.browser = 0;
} else {
return ++this.getBrowser.browser;
}
}
window.BRB = new BRB();
})(window);
console.log(BRB.getBrowser());
console.log(BRB.getBrowser());
console.log(BRB.getBrowser());
console.log(BRB.getBrowser());
http://jsfiddle.net/5DheZ/
You should define the browser variable in another place:
(
function(window){
if(window.BRB) return;
var browser = null;
var BRB = function(){}
BRB.prototype.getBrowser = function(){
if(browser === null){
browser = 0;
}
return browser++;
}
window.BRB = new BRB();
})(window);
console.log(BRB.getBrowser());
console.log(BRB.getBrowser());
console.log(BRB.getBrowser());
console.log(BRB.getBrowser());
jsfiddle http://jsfiddle.net/5ByYR/1/
And if you are able to assign an object instead of function to getBrowser:
(
function(window){
if(window.BRB) return;
var BRB = function(){}
BRB.prototype.getBrowser = {
browser: null,
get: function() {
if(this.browser === null){
this.browser = 0;
}
return this.browser++;
}
}
window.BRB = new BRB();
})(window);
console.log(BRB.getBrowser.get());
console.log(BRB.getBrowser.get());
console.log(BRB.getBrowser.get());
console.log(BRB.getBrowser.get());
You probably intended for the getBrowser method to be an IIFE closure for the result:
BRB.prototype.getBrowser = (function(){
var browser = null;
return function(){
if(browser === null){
browser = 0;
}
return browser++;
}
})();
This way the browservariable is not reinitialized on each function call.
UPDATE
You could use a property instead of a variable scoped in a closure for the browser value:
BRB.prototype.getBrowser = function() {
if(!this.browser){
this.browser = 0;
}
return this.browser++;
}

Ensure only one setTimeout runs (is active) at a time?

The recursive setTimeout function getRandomProducts is called onload in the html body tag, and so is constantly iterating.The function setCategoryTree is being called onclick from the links in a nested ul of a navigation-bar. This function then passes the variable mainCategory to getRandomProducts, in which the variable is declared globally to maintain its' initialization....So, what I am trying to do is reset the getRandomProducts function when a link is clicked in the navigation-bar, and pass the category name from the link that was clicked. However, clearTimeout does not seem to be working and so the iterations occur a lot more frequently as there are then multiple recursive loops executing simultaneously.And not only that, but my global variables are not storing data from setCategoryTree as intended (basically I am trying to use the global variable similarly to a static-variable). I have discerned all of this behavior with the window.alert that is commented out.Here is the relevant Javascript code:
var mainCategory = ""; // initialized from setCategoryTree
var category = mainCategory;
function getRandomProducts(category)
{
//window.alert(category);
if(typeof category == "undefined")
category = "all";
else
clearTimeout(t);
var req = new XMLHttpRequest();
var products = document.getElementById("products");
req.onreadystatechange = function()
{
if( (req.readyState == 4) && (req.status == 200) )
{
var result = req.responseText;
products.innerHTML = result;
}
}
req.open("GET", "default.php?category=" + category, true);
req.send(null);
var t = setTimeout("getRandomProducts()", 1000);
}
function setCategoryTree(link)
{
var categoryTree = document.getElementById("categoryTree");
/* climbing the DOM-tree to get the category name (innerHTML of highest "a" tag) */
mainCategory = link.parentNode.parentNode.parentNode.getElementsByTagName("a")[0].innerHTML;
var subcategory = link.innerHTML;
categoryTree.innerHTML = "-- " + mainCategory + " -- " + subcategory;
getRandomProducts(mainCategory);
}
You are setting the variable t within the function. The next time this function gets called the var t will not be available for you.
Therefore, Set the variable above the function (not in it)
var randomProductsTimeout = false;
function getRandomProducts(category){
randomProductsTimeout = setTimeout()[..]

JavaScript "is not a function" error when calling defined method

This is my code:
request_xml: function()
{
http_request = false;
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType)
{
http_request.overrideMimeType('text/xml');
}
if (!http_request)
{
return false;
}
http_request.onreadystatechange = this.response_xml;
http_request.open('GET', realXmlUrl, true);
http_request.send(null);
xmlDoc = http_request.responseXML;
},
response_xml:function ()
{
if (http_request.readyState == 4)
{
if(http_request.status == 404 && countXmlUrl<=3)
{
countXmlUrl++;
realXmlUrl = xmlUrl[countXmlUrl];
this.request_xml();
}
if (http_request.status == 200)
{
xmlDoc = http_request.responseXML;
alert("need to update3");
this.peter_save_data();
}
}
},
peter_save_data:function()
{
// removed function code
},
Strangely, the alert fires without a problem but the function call underneath gives me this error:
Error: this.peter_save_data is not a function
Calling the same damn function from another function elsewhere works fine.
You could do this, right before you call the XML generation.
var that = this;
and later...
that.peter_save_data();
Because this frequently changes when changing scope by using a new function, you can't access the original value by using it. Aliasing it to that allows you still to access the original value of this.
One important piece of the puzzle that is missing is how response_xml is being called. This is important, because it will change what this is (see Jared's comment).
Remember that this can be thought of as (roughly) "the receiver of the method call". If response_xml is passed directly to use as a callback then of course it won't work -- this will likely be window.
Consider these:
var x = {f: function () { return this }}
var g = x.f
x.f() === x // true
g() === x // false
g() === window // true
Happy coding.
The "fix" is likely just to change how response_xml is being called. There are numerous ways to do this (generally with a closure).
Examples:
// Use a closure to keep he object upon which to explicitly invoke the method
// inside response_xml "this" will be "that",
// which was "this" of the current scope
http_request.onreadystatechange = (function (that) {
return function () { return that.response_xml() }
}(this)
// Or, alternatively,
// capture the current "this" as a closed-over variable...
// (assumes this is in a function: var in global context does not create a lexical)
var self = this
http_request.onreadystatechange = function () {
// ...and invoke the method upon it
return self.response_xml()
}
Personally, I would just use jQuery or similar ;-)
If you want a class-like behavior, use the right syntax, The libraries that use that, are using JSON to pass a parameter to a function that makes a class out of it.
function MyClass(CTOR paarams){
var response_xml=function ()
{
if (http_request.readyState == 4)
{
if(http_request.status == 404 && countXmlUrl<=3)
{
countXmlUrl++;
realXmlUrl = xmlUrl[countXmlUrl];
this.request_xml();
}
if (http_request.status == 200)
{
xmlDoc = http_request.responseXML;
alert("need to update3");
this.peter_save_data();
}
}
}
var peter_save_data=function()
{
// removed function code
}
}
var Test = new MyClass(somthing,another_something);
Test.response_xml();
//etc etc.
Or, use the libraries like Mootools where you can do it as JSON:
var T = new Class({
response_xml:function ()
{
if (http_request.readyState == 4)
{
if(http_request.status == 404 && countXmlUrl<=3)
{
countXmlUrl++;
realXmlUrl = xmlUrl[countXmlUrl];
this.request_xml();
}
if (http_request.status == 200)
{
xmlDoc = http_request.responseXML;
alert("need to update3");
this.peter_save_data();
}
}
},
peter_save_data:function()
{
// removed function code
}
});
var X = new T();//etc etc

Categories

Resources