Cannot instantiate a class when script is injected into document dynamically - javascript

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);

Related

Cannot set property 'classRules' of undefined

am just don't know what happened it was work correctly .... What's most reasons that led us to this error ????
I was trying to run my website locally then this error comes to me from I don't know so what is this error mean and how can I solve it
the error occurs in this code .... actually , its complete website and I'm a beginner with JS and SO so please help me
// disable class and attribute rules defined by jquery.validate
$.validator.classRules = function() {
return {};
};
$.validator.attributeRules = function() {
return {};
};
Your Code tries to access an non existing JQuery namespace. You are either missing some sort of JQuery plugin, or you need to create on your self.
If you would like to create the validator namespace you can use such sample code as described here
(function ($) {
// do not overwrite the namespace, if it already exists
$.validator= $.validator|| {};
$.validator.classRules = function () { return {};}
$.validator.attributeRules = function () { return {};}
})($);

How is this JavaScript object created for this bookmarklet?

I am trying to reverse engineer a bookmarklet that uses CasperJS.
It creates an object called __utils__ that I can execute console commands with.
The link to the bookmarklet is here:-
http://casperjs.org/api.html#bookmarklet
Which references this JavaScript file:-
https://raw.github.com/n1k0/casperjs/master/modules/clientutils.js
I have searched through the whole source code and I cannot find a reference to how this object is created.
Any pointers would be appreciated.
The bookmarklet simply runs a small snippet of JavaScript code that appends a link to the clientutils.js to the document's end. After that, it will run an anonymous function every 50 milliseconds that checks if the script has loaded (and has made the ClientUtils function available), and if it has, it stops running the function and creates window.__utils__, thus making it available in the console. Here's the actual bookmarklet code in a more readable format. It should be pretty straightforward to understand:
(function () {
void(function () {
if (!document.getElementById('CasperUtils')) {
var CasperUtils = document.createElement('script');
CasperUtils.id = 'CasperUtils';
CasperUtils.src = 'https://raw.github.com/n1k0/casperjs/master/modules/clientutils.js';
document.documentElement.appendChild(CasperUtils);
var interval = setInterval(function () {
if (typeof ClientUtils === 'function') {
window.__utils__ = new window.ClientUtils();
clearInterval(interval);
}
}, 50);
}
}());
})();
Look at the source of api.html. After Just drag this link look at the JS in the href attribute. Near the end it contains:
window.__utils__=new%20window.clientUtils();

Accessing global variable from other JS file

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.

nodejs + jsdom, jQuery strange behavior

The code below is just a small snippet from my server.js file just to run the test provided by the jsdom documentation.
var window = jsdom.jsdom().createWindow();
jsdom.jQueryify(window, './jq.min.js' , function() {
console.log('inside');
window.$('body').append('<div class="testing">Hello World, It works</div>');
console.log(window.$('.testing').text());
console.log('end');
});
The output I get literally is just inside and then the server hangs and never returns. I've added a debug statement console.log(window); to see if the window object is truly being created, and I do end up with a fairly large output statement detailing the object's contents. One thing I did notice however is that the output does not show that $ is a defined method of the window object and in fact, console.log(window.$); renders undefined.
I understand jsdom is still in dev mode, but is there something I'm missing here?
Just as some background, I have tried several variations of the code, including using the jsdom.env() method and also building a document from existing HTML markup, neither of which rendered expected results either.
I hope this code snippet helps you:
createWindow = function(fn) {
var window = jsdom.jsdom().createWindow(),
script = window.document.createElement('script');
jsdom.jQueryify(window, function() {
script.src = 'file://' + __dirname + '/some.library.js';
script.onload = function() {
if (this.readyState === 'complete') {
fn(window);
}
}
});
}
createWindow(function(window) {
// Do your jQuery stuff:
window.$('body').hide();
});
from here

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