0

I am trying to create a Chrome extension using CrossRider and am struggling with how to create a global variable.

My extension is essentially going to dynamically append a few JavaScript files to the page if a button is clicked, and I need it to also create a global variable and set some properties.

I tried the following:

appAPI.ready(function($) {
    console.log('inside crossrider extension ready()');
    window.foobar = 'barfoo';
    return;
});

When I refresh the page, the message inside crossrider extension ready() is printed out to the console, so I know the extension is loaded and working, but when I try executing window.foobar or foobar in the console an error is thrown saying it's undefined.

This is my first time creating an extension, so what am I missing here? Why isn't the global variable I create inside of CrossRider's appAPI.ready() function available outside of it?

Nate
  • 26,164
  • 34
  • 130
  • 214
  • 2
    How do you intend to use the global variable? Variables created in the __extension.js__ file are volatile since the extension page scope is recreated every time a page is loaded (as is the windows object that is in the HTML page scope). If you want persistent global variables, you have 2 basic choices. Either (1) store it in the background scope and use messaging to pass it between scopes (persists while background runs) or (2) store it in the local extension's local database ([appAPI.db.async](http://docs.crossrider.com/#!/api/appAPI.db.async)). [**Disclosure**: I am a Crossrider employee] – Shlomo Feb 27 '15 at 12:30
  • @Shlomo, `Variables created in the extension.js file are volatile since the extension page scope is recreated every time a page is loaded` -- so are all variables created in JavaScript? I don't need a `persistent global variable`, I just want the code in the extension to be able to interact with global variables on the page. – Nate Feb 27 '15 at 12:45
  • @Shlomo, For example, I mentioned I'm using the extension to load an external JS file. This file has global variables defined in it. I want the extension code to be able to modify these global variables. I would also like to go the other way -- creating global variables in the extension which the loaded script can read and modify. Thanks for your help! – Nate Feb 27 '15 at 12:46

1 Answers1

3

I can't find a duplicate target, so I'll explain what's happening.

I don't know the Crossrider terminology, but when a Chrome extension executes code in a page, this is called a Content Script.

However, the code does not execute in the same context as the page itself. It's called an isolated world and means, among other things, that the window object is not shared.

Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page. It looks to each content script as if there is no other JavaScript executing on the page it is running on. The same is true in reverse: JavaScript running on the page cannot call any functions or access any variables defined by content scripts.

So if you want to set a variable accessible to the page, you need to set it in the page context. How? There are many ways, but they all amount to inserting a <script> element into the page.

var script = document.createElement('script');
script.textContent = "window.foobar = 'barfoo';";
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);

All of that assumes that you don't control the page in question. If you do, there are other ways of communicating the the page, because DOM is shared. You can, for instance, raise a custom DOM event if the page listens to it.

Community
  • 1
  • 1
Xan
  • 74,770
  • 16
  • 179
  • 206
  • But I can use jQuery selectors to get/modify elements from the DOM, such as `$('body')` just fine, so why are variables any different than DOM elements? – Nate Feb 27 '15 at 15:07
  • 1
    _"..because DOM is shared"_ Read up on the isolated world aspect. – Xan Feb 27 '15 at 15:11
  • Well this is majorly inconvenient. I don't fully understand why they did it like this since the variables can still be accessed by injecting a script that saves the variable data to a dom element and then that can be read (or the opposite direction to write data to variables). I understand the need for isolation, but it would make sense to have an API method available to act as a go-between between the two environments. Oh well, that's web development for you.. Thanks for your help. – Nate Feb 27 '15 at 22:13
  • The article describes the reasons pretty well. The main one being that you don't have to worry about incompatibilities between the content script and the page. Not to mention huge security implications of exposing privileged extension code to the page. – Xan Feb 27 '15 at 22:15
  • 1
    @Xan Thanks for stepping in and explaining it so nicely. Nate: If you need to communicate with the page, consider using either [Crossrider Page Events](http://docs.crossrider.com/#!/api/CrossriderAPI.events) or pass variables between the scopes as described in [How to pass the value of a page variable to the extension scope](http://docs.crossrider.com/#!/guide/howto_get_page_variable). – Shlomo Mar 01 '15 at 08:36