1

This question is about a similar javascript scope problem that I asked yesterday. I hope you can help me resolve this issue.

I am working with a Chrome extension. options.html saves to localStorage a new user email as "user" and calls refreshUser() function in background.html:

//save entered gmail address
document.getElementById("save").addEventListener(
    "click", function ()
    {
        var user = document.getElementById("getEmail").value;
        localStorage.setItem("user", user);
        chrome.extension.getBackgroundPage().refreshUser();
    } , false)

Then I save the email as "newUser" in background.html. The problem is that newUser is updated inside refreshUser() but it is null outside refreshUser():

newUser = localStorage.getItem("user");
console.log("first newUser " + newUser);
//newUser=null

function refreshUser () 
{
    newUser = localStorage.getItem("user");
    console.log("newUser inside of refreshUser function " + newUser);
    //newUser is updated with saved email in localStorage
}

console.log("newUser after refreshUser() " + newUser);
//newUser=null

Why is newUser local to refreshUser() while it is defined without the var keyword? Thanks for your help!

Update

In response to pimvdb's answer I copy the code for my background.html. If I want to use newUser in formData as indicated which function do I need to call inside refreshUser()? Thanks.

<html>
<script>

newUser = localStorage.getItem("user");
console.log("first newUser " + newUser);

function refreshUser () 
{
    newUser = localStorage.getItem("user");
    console.log("newUser inside of refreshUser function " + newUser);
}

console.log("newUser after refreshUser() " + newUser);

//I want to user newUser below in formData  
chrome.browserAction.onClicked.addListener(function(tab) 
{
    chrome.tabs.getSelected(null, 
    function(tab) 
    {
        // Send a request to the content script.
        chrome.tabs.sendRequest(tab.id, {action: "getDOM"}, 
        function(response) 
        {
            var firstParagraph = response.dom;

            var formData = new FormData();
            formData.append("url", tab.url);
            formData.append("title", tab.title);
            formData.append("pitch", firstParagraph);
            formData.append("extension_user", "abc@gmail.com");
            //I want to user newUser here:
            //formData.append("extension_user", newUser);
            console.log("newUser inside formData: " + newUser)

            var xhr = new XMLHttpRequest();
            xhr.open("POST", "http://ting-1.appspot.com/submithandlertest", true);
            xhr.onreadystatechange = 
            function (aEvt) 
            {
                if (xhr.readyState == 4) 
                {
                    if (xhr.status == 200)
                    { 
                        console.log("request 200-OK");
                        chrome.browserAction.setBadgeText ( { text: "done" } );
                        setTimeout(function () 
                        {
                            chrome.browserAction.setBadgeText( { text: "" } );
                        }, 2000);
                    }
                    else
                    {
                        console.log("connection error");
                        chrome.browserAction.setBadgeText ( { text: "ERR" } );
                    }        
                }        
            };
            xhr.send(formData);
        }); //chrome.tabs.sendRequest
    });
});


</script>
</html>

Update to answer pimvdb's comment:

The problem I am having is that background.html is loaded when the browser is opened, but the email is saved in options.html afterwards. So refreshUser() tells background.html to get the newUser from localStorage. Then I need to use "newUser" in formData like this:

formData.append("extension_user", newUser);

But the way I have it now "newUser" outside refreshUser() is null. What am I missing?

Update to clarify why some logs are not showing in console

This is what I do:

1. I reload the extension and start with localStorage empty
2. I use the extension to save a bookmark
3. all 3 logs are null as expected

 first newUser null
 newUser after refreshUser() null
 newUser inside formData: null
 request 200-ok

4. now I save user email in options as abc@gmail.com
5. now I use the extension again to save a bookmark
6. now refreshUser is executed and the log inside the function says abc@gmail.com and formData log says abc@gmail.com

newUser inside of refreshUser function abc@gmail.com
newUser inside formData: abc@gmail.com
request 200-OK

7. but what confuses me is that now the first 2 logs do not show in the console. Why?
Community
  • 1
  • 1
Zeynel
  • 13,145
  • 31
  • 100
  • 145

3 Answers3

2

It's global, but you're accessing it at the wrong time.

function refreshUser () { ... } is just a function declaration; nothing is really executed. Both logs outside that declaration run immediately, at which point the localStorage item has not been set (i.e. is null).

Your wording "newUser after refreshUser()" is rather ambigious. It's indeed executed after the declaration, but newUser has not been changed at all, so both logs outside the function log null. You cannot access it at the time it has not been set yet what you seem to be expecting.

The following should log it fine, since the global variable has been updated. Just call it after setting it inside refreshUser.

function otherFunction() {
    // logs the global variable 'newUser', which is thus indeed global
    console.log("newUser inside otherFunction: " + newUser);
}

function refreshUser () 
{
    newUser = localStorage.getItem("user");
    otherFunction();
}
pimvdb
  • 151,816
  • 78
  • 307
  • 352
  • thanks for the answer. Since there are nested functions in `background.html` I was not sure what `otherFunction()` I need to call from `refreshUser`. I updated my question with `background.html`, can you help with the function to call from `refreshUser()`? Thanks again. – Zeynel Oct 27 '11 at 15:42
  • @Zeynel: You don't need `otherFunction`; it was more like a "proof" that it's global. I'm not sure what function you want to call. What you have now should work, although `refreshUser` doesn't do much. What exactly do you want to happen when `refreshUser` is executed? Do you want to execute the xhr part again? – pimvdb Oct 27 '11 at 16:24
  • ok, you are right, now this works and when `refreshUser` is called by options page `newUser` in `formData` is updated with the new saved email. But I still do not understand why the first two logs do not show when `refreshUser` is executed. Your answer solved the problem thanks, but in terms of understanding the flow of the program can you help why the first two logs are not showing? I updated the question with what I am trying to do. Thanks again. – Zeynel Oct 27 '11 at 17:23
  • 1
    @Zeynel: Those two functions (`first newUser` and `newUser after refreshUser()`) are not inside any functions. They show up as soon the script is loaded, but do not show up any more times. When you save the bookmark the first time, you'll see the first two logs because they got logged when the script was loaded. They have nothing to do with using the extension to save the bookmark (i.e. they do not run because of interaction). – pimvdb Oct 27 '11 at 20:47
2

You haven't called refreshUser() in the snippet you posted, so it won't be set.

Try calling it, then checking the global newUser.

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
  • Thanks for the answer, as I mentioned on the other comment below, the function where I need to use `newUser` in `background.html` is an anonymous function, how do I call it within refreshUser()? – Zeynel Oct 27 '11 at 16:27
1

I just want to comment on the practice of defining variables but it's too long for a comment.

You don't ever want to define new variables without var keyword, it will lead to all sorts of trickery and unexpected results. If you want to ensure it's a global variable use the global object.

var globalObject = this,
    globalVariable = 1; //or globalObject.globalVariable = 1;

function example(){
var globalVariable;

globalVariable = 2 //This will not set the global variable and you can see it's not intended either since we used var
console.log( globalObject.globalVariable ); 
globalObject.globalVariable = 2 // This will set the global variable, the intent to do so is very explicitly shown
console.log( globalObject.globalVariable ); 
}

example();
//1
//2
console.log( globalObject.globalVariable, globalVariable );
//2 2
Esailija
  • 138,174
  • 23
  • 272
  • 326