I'm building an app with Browserify, so everything is packaged up into commonJS modules and separated out of the global name space, which is generally a great state of affairs.
I've had to open up another page inside of an iframe which opens as a modal in my app. Once the user saves his work inside of that page that page needs to call out to my app to tell it to close the modal.
The only way I know of to call outside of an iframe is to use parent.window. But I'm unclear how to get from the global namespace inside of the modules packaged up with browserify.
I have tried to assign a function to an identifier on the window object within one of my modules, but after the code runs, if I interrogate the window object, my function is not there.
I have tried to follow the example in this post, but I'm not having any luck.
Defining global variable for Browserify
Thanks
All you have to do is assign the object explicitly to the window object and it will be there. For instance, with jQuery, you'd just make sure something like this was present in the code you're bundling with Browserify:
window.$ = window.jQuery = require('jquery');
Related
On a website, I bundle all the javascript with Gulp into one bundle file. This includes jQuery, which I import into all the JS files that require it.
I include the Google Tag Manager (GTM) directly in the HTML. However, some of the custom tags require jQuery, which is undefined according to browser console output. I assume jQuery is not exposed outside the bundle.
How do I expose jQuery from the bundle so external scripts such as GTM can use it?
Solution
Got the idea from jqfundamental's jQuery Basics Guide:
import $ from 'jquery';
// make jquery available to all imports using `window` to load jQuery
window.jQuery = window.$ = $;
With these two lines, the jQuery version loaded via import (in my case the one I specified in my Node package.json) will be assigned to the window object, from which most jQuery plugins as well as GTM custom tags load jQuery.
I put this statement on top of my main js file. This way I make sure that all imported jQuery plugins can access jQuery via window, as well.
Why this works
For everyone not completely aware of it: All properties of the window object are globally available with their key name:
window.foo = 'someValue';
console.log(foo);
// outputs 'someValue' even if used in a different scope/file/module
If this doesn't work
Check the last line of your plugin code: Some plugins load jQuery from this.jQuery instead of window.jQuery.
Usually, this in JS scripts on the top level points to window, so above approach works. However, in ES6 modules - and as such the bundle code is run in the browser - this is undefined (see this exploringjs table for reference).
I haven't found a good solution other than adjusting the plugin code to use window.jQuery. See this related question (unanswered at the time of writing).
Reason for this issue
Stumbled upon this issue which explains the reason for this behavior quite well: The jQuery code contains a conditional testing for module being defined and an object:
if ( typeof module === "object" && typeof module.exports === "object" ){
// set jQuery in `module`
} else {
// set jQuery in `window`
}
In Nodejs, module is an object even in the browser, thus jQuery is not globally available by default, but only in the current scope of the import.
I'm having a problem with the scoping of this inside of an angular-ui bootstrap modal. When I run the following code outside of a modal I have no problems with it:
var GlobalVariable = GlobalVariable || {};
(function(){
doSomethingWith(GlobalVariable.field);
})();
When called outside of the $modal GlobalVariable.field is perfectly accessible. As soon as I run this code inside a $modal, GlobalVariable.field is undefined. Now I can fix this problem by directly accessing window.GlobalVariable.field inside the $modal dialog but the problem is that the doSomethingWith method in this case is a 3rd party library which needs access to the global variables. I'm not about to go through all the third party libraries and add "window." on to all of the globally scoped variables.
I know that when I call $modal.open passing in some HTML that it gets mangled through the angular $compile function (which I presume eval()s the HTML as part of the process). My guess is that when $compile processes it, it assigns it a fresh this object meaning we don't inherit all of the globally scoped variables from window.
Is there any way that I can get angular's $compile to force 'inheritance' of the window's global variables all the way down to my modal?
Have a look at this Plunker that I generated from the Angular-UI bootstrap documentation:
http://plnkr.co/edit/jMcvTBDcrkPU7p4gFejT?p=preview
resolve
As you can see, the modal creates a new scope, so anything you want to use inside that scope must be passed in using "resolve" and returned. There's no need to force inheritance when you can just pass whatever you need in.
Writing some JS and would love to enumerate specifically what I'm importing from other files in the main body of my JS script. Is there an equivalent to C's extern declaration for JS?
Thanks!
Variables declared outside of function scope are global in JavaScript. For example, if you have two JS files and declare a variable 'myObject' in the first file, it will be in scope for the second file, and declared for use if the first file is loaded into the browser already.
If you need access to objects between JS files, it's good practice to expose one object to the global namespace and declare fields and methods on that object.
File 1:
var myObject;
myObject.myField = "Field!";
File 2:
myObject.prototype.myFunction = function () {
return this.myField;
};
Hope this helps, happy to hear other suggestions and open to corrections :D
There's no equivalent to a C extern declaration in JavaScript because JavaScript doesn't require variables to be declared before they're used the way C does.
If your JavaScript code depends on some properties being defined on the window object, just document those properties in a comment near the top of the file.
Sadly, Javascript has no built in features for controlling what gets imported or not.
By default, all sripts loaded in a page will write their global variables to the same shared global scope. The only way around this is writing your scripts so that they create as few global variables as possible, using the module pattern.
Alternatively you can use one of the module systems extensions that people came up with. For example you can write your scripts using the CommonJS module system and it will make it make it so that top level var declarations in your scripts arent seen from other scripts and lets you explicitly export the values you like. Some runtimes like nodejs can run CommonJS modules natively and for the ones that dont, like browsers, you can use a tool like browserify to compile the commonjs modules into a single file that can be put into a script tag and that will still do the right thing.
My problem is the following. I'm using different context (require.js ones) to load some widgets as there have different baseUrl. Each widget need some commons modules like text plugin or css plugin so currently I need to define them into the require config through the paths object. But in this case, each plugin will be loaded each time you require a widget as they belong to different context while they are actually the same.
To be more clear, here an example:
app1_require = require.config({context:'app1',baseUrl:'/app1',paths:{text:'../text'}})
app2_require = require.config({context:'app2',baseUrl:'/app2',paths:{text:'../text'}})
In using app1_require then app2_require, I will have the plugin text injected twice into the DOM (two script tag). How can I proceed to set the text module as a global one which can be used within all contexts? Note that I'm also using a require without any context to load some global dependencies.
Thanks in advance ;)
I have an HTML file which imports two files:
graph.js and main.js
The main file contains logic which accesses a phone's accelerometer/records acceleration and it is a purely javascript file. The Graph.js file contains a single JQuery function $(.....)
Is it possible to access a variable in main.js from graph.js?
Yes jQuery is written in JavaScript and it can access any variable declared in that page via import of other JavaScript files. As you are trying to access variable in onload of document, I don't see any problem, because other scripts should already have been loaded before that.
Yes.
if it is in global scope, yes.
It should be, so long as the main.js loads first and if you set it as a global variable.
You make a global variable by creating it outside of a function. If needed, you can create it outside a function, then set it inside a function in the main.js file.
You can freely share variables between different JS files (a jQuery file is just a JS file) in several different ways:
Define the variables in the global scope, then they can be accessed anywhere.
Define variables on the window object. This makes them globally accessible even if your code defining the variables isn't in the global scope.
Define variables as properties on any object that you can get to from your code. So, if you have a global config object called myConfig, you could define properties on it like myConfig.count = 0; and you can then access myConfig.count from anywhere. This is often referred to as namespacing and creates only a single global object which you then add multiple properties to.
Define a globally accessible function that returns your data that you can call from anywhere.
When designing how this works, remember that it's generally better to introduce as few globally accessible symbols as possible because each one is an opportunity for a conflict with some other code in the page.