Accessing global variable from other JS file - javascript

This is my main file:
$(document).ready(function () {
function Page() {
this.menu = new Menu();
this.management = new Management();
this.text = "text";
}
window.Page= Page();
});
Now I want to access the Page from every other JS file:
I tried this:
console.log(Page.text);
Gives me : Uncaught ReferenceError: Page is not defined
Tried this:
console.log(window.Page.text);
Gives me : Uncaught TypeError: Cannot read property 'text' of undefined
What am I doing wrong?

Your issue is that within the Page function you are not creating any new object on the global context. You are creating a new Menu and new Management instance but on the current context.
Plus by calling the Window.Page = Page(), you are assigning the result of the Page function (which is void) to the window.Page object.
I suggest you do something like :
//- from any js file
function createPage() {
var newPage = { title : 'new page', count : '2' };
return newPage;
}
window.Page = createPage();
...
//- and from other js file
$(document).ready(function () {
alert(window.Page.title);
});
Note, I have replaced your menu and management properties with dummy content for this sample. Sample available # this JSFiddle
Update : Code has been updated to illustrate the multiple js file proper usage.
Hope this helps

Function definitions don't need to be inside the document.ready() function. Only immediate actions that need to take place when the DOM is ready need to be put in there. So move the function to the toplevel.

You need to use window.Page = new Page();.

Either
window.Page = new Page();
or
function Page(){
this.menu = new Menu();
this.management = new Management();
this.text = "text";
return this;
}
window.Page = Page();
Then make sure other scripts don't try to use window.Page before it has been declared. You declare it in document.ready() callback function, so it's only going to be accessible once the DOM is ready and the callback function has been fired.
Edit:
without the context I'm not sure this is exactly what you're trying to do, but I think you just need a global Page object with some properties/methods. The easiest way to create it would be
window.Page = {
menu : new Menu(),
management = new Management(),
text = "text"
};
without the document.ready() wrapper.
Now obviously Menu and Management need to be defined before this code is executed. If any of these functions relies on DOM just move all your scripts to the end of the document. Any script that needs access to window.Page has to be included after this one.

Related

Cannot instantiate a class when script is injected into document dynamically

I am experimenting with Classes available in javascript and have setup a simple test case as follows:
<script src="myclass.js></script>
<script>
var test = new MyClass();
</script>
myclass.js contains the following:
class MyClass {
constructor() {
}
}
This works as expected.
However, if I dynamically load "myclass.js" using jQuery.getScript() function the browser returns the following error:
Uncaught ReferenceError: MyClass is not defined
Things I have double checked are:
The code to instantiate the class is placed within the success callback of the getScript function
And also that the script is actually being loaded and executed (with a simple console log)
However I seem to have a brick wall with this. Is there any reason why a class cannot be instantiated from if the file containing the class is loaded from a javascript file using the jQuery.getScript function?
This is the code which does not work:
<script>
$(document).ready(function() {
$.getScript('myclass.js', function () {
var test = new MyClass();
});
});
</script>
Testing on Chrome Version 71.0.3578.98 (64-bit)
Have a look at this question and its answers as well as the documentation such says the success callback is run after loading but not necessarily after executing the script.
To sum up, it might suffice to run your code by appending a then (or done) handler:
$.getScript(url).then(function() {
var test = new MyClass();
});
If this is not enough you should fall back to use a setInterval-triggered check for the existence of the class (stop the interval after finding the class).
This way you are avoiding any dependency on the specific browser behavior when the script gets executed after loading it.
function afterScriptExecuted() {
var test = new MyClass();
}
function testScriptExecuted() {
return window.MyClass !== undefined;
}
$.getScript(url).then(function() {
var id = setInterval(function() {
if (testScriptExecuted()) {
clearInterval(id);
afterScriptExecuted();
}
}, 50);
});
In the end, only the following approach worked for me (rather than using jQuery.getScript)
var script = document.createElement('script');
script.onload = function () {
var test = new MyClass();
};
script.src = '/myclass.js';
document.head.appendChild(script);

javascript context changing using jQuery.fn.extend

I try to create a method that can be called from the created DOM element corresponding to my B class, like that:
$("#" + data.selectedId).eventCallback(data);
My eventCallback is defined in a mother class A, as you can see in the following code:
function A (){
this.addToPage = function () {
...
var context = this;
// This call is well overridden
context.onEvent("toto");
jQuery.fn.extend({
// This call uses A's method every time
eventCallback: function (data) {context.onEvent(data);}
});
};
this.onEvent = function (data) {
console.log("to override");
};
}
function B (){
this.onEvent = function (data) {
console.log("overridden");
};
}
B.prototype = Object.create(A.prototype);
The problem is, as commented, that I seem to not being able to use the same context when I enter the block jQuery.fn.extend. Is there a better (and cleaner) way to do it? Do I miss something?
Edit, to clarify:
The A class define the structure of widgets which are set in my html document (so to my mind an A instance is somehow linked to a part of the DOM).
As a user, I want to be able to select a widget that call a method (which definition is depending on B).
So My idea was to implement a callBack in the class and then make it callable from the DOM objects created with an A instance.

How can I use a javascript function globally in Drupal 7

How can I use a javascript function globally in Drupal 7.
I have my javascript file set up like this and add it using drupal_add_js():
(function($) {
function add_if_country_is_not_usa() {
// Check what country it is
// Update text, image, etc.. of a block.
}
});
In my block WYSIWIG I added the following code (The reason I add it in the WYSIWIG is because I want it to update before the page is fully rendered):
<script type="text/javascript">
add_if_country_is_not_usa();
</script>
But I get the following error:
Uncaught ReferenceError: add_if_country_is_not_usa is not defined
(anonymous function)
I read about adding functions to Drupal behaviors but that happens on document ready. I want to run the function as soon as the block is shown.
Any ideas?
Either define in the global scope, or do like below:
(function($) {
function add_if_country_is_not_usa() {
// Check what country it is
// Update text, image, etc.. of a block.
}
// set as a property of the global object `window`
window.add_if_country_is_not_usa = add_if_country_is_not_usa;
});
Not sure if this is the best way but I ended up being able to get it work using a namespaces. I call myGlobalObject.add_if_country_is_not_usa() from my block and it works now.
var myGlobalObject = mySingleGlobalObject || { 'country': {} };
(function ($) {
myGlobalObject.country = '';
myGlobalObject.add_if_country_is_not_usa = function() {
// Check what country it is
// myGlobalObject.country = 'US';
}
})(jQuery);

Calling a closure from a popup window?

I have an aspx page that has a reference to index.js inside the js I have a closures like thes one below, then from the page I open a popup window which has a reference to page1.js , Is there any way to call the closure and assign it to a variable in page.js, so I can use the closure methods and update the _var1.
Im opening the popup window within the same domain as the parent index.aspx page. I already tried using code in page.js like: var _closure = window.opener.UI_Methods(); but I got the following error: Unable to evaluate the expression. Call was rejected by callee. in the Immediate Window on VS 2010 when debugging.
Is there a way I can call a closure in the parent page and update variables by calling the closure methods?
UI_Methods = function(){
var _var1 = var1 || null;
var _setVar1 = function(var1){
_var1 = var1;
};
var _getVar1 = function(){
return _var1;
};
return {
SetVar1 : _serVar1
};
};

Problem accessing global javascript variables

My application has something like the following structure
window.object1;
window.object2;
$(document).ready(function() {
window.object1 = new type1object();
});
function type1object() {
//lots of code
this.property = 'property';
window.object2 = new type2object();
}
function type2object() {
//lots of code
this.property = new type3object();
}
function type3object() {
//lots of code
console.log(window.object1);
this.property = window.object1.property;
}
The problem is that whenever I try to access window.object1 from anywhere other than the document ready callback it comes back as undefined, this is even though when I inspect the DOM window.object1 is defined exactly as I expect it to be.
I've tried doing the same as above but using simple global variables instead (i.e. var object1 instead of window.object1) ... Tried declaring initial dummy values for object1 and object2 in various places... but run up against the same problem.
Does anyone know why I can't access my global variables globally?
You have to make sure you are evaluating window.object1 after initiating it.
That is, in your case, only after document.ready finished executing
If you look at this example below you can see that at click both are initialized.
<html>
<body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
<script>
$(document).ready(function() {
window.object1 = new type1object();
window.object2 = new type2object();
//console.log(window.object1);
});
$(document).click(function(){
console.log(window.object1);
console.log(window.object2);
});
function type1object() {
}
function type2object() {
}
</script>
Since you are not setting the value of window.object1 until you are inside the document ready function, you wont be able to access it until it has run.
Nothing in your code shows that you couldn't just remove that document ready call altogether. It is generally reserved for waiting for elements to load in the dom, which it doesn't seem like you are doing. If you somehow do have elements that need to be waited on inside of code that isn't there, just put your script at the bottom of the page, right above the tag. This will do the equivalent of document ready.
writing the code really stripped out made the answer fall out - I was creating something that referenced object1 during the construction of object1.
So I changed it to this, so that the object exists (though with no content) before anything tries to reference it:
window.object1;
window.object2;
$(document).ready(function() {
window.object1 = new type1object();
window.object1.construct();
});
function type1object() {
//lots of code
this.construct = function() {
this.property = 'property';
window.object2 = new type2object();
};
}
function type2object() {
//lots of code
this.property = new type3object();
}
function type3object() {
//lots of code
console.log(window.object1);
this.property = window.object1.property;
}

Categories