1

I am trying to load a class dynamicly and check if it was loaded before.
the code below is not working, any idea why?

I am unable to understand why is this part not working:

if (typeof window['Car'] == 'undefined')

full source:

if (typeof window['Car'] == 'undefined') {
    alert("Car class not loaded!");
   }
      
var head = document.getElementsByTagName('head')[0];

var script = document.createElement('script');
script.src = 'http://m.uploadedit.com/bbtc/1572125047736.txt';
script.type = 'text/javascript';

head.append(script);
      
 setTimeout(function(){
           if (typeof window['Car'] == 'undefined') {
          alert("Even After X seconds, Car class not loaded!");
        }else{
          alert("After X seconds, Car class loaded!");
        } 

  }, 3000);
       

Update I am adding the solution source here, just in case the fiddle is lost:

function testClass(cls) {
  return eval("typeof " + cls + " === 'function'");
}


if (!testClass('Car')) {
        console.log("Car class not loaded when starting as expected!");
}

var head = document.getElementsByTagName('head')[0];

var script = document.createElement('script');
script.src = 'http://m.uploadedit.com/bbtc/1572125047736.txt';
script.type = 'text/javascript';

head.append(script);

 setTimeout(function(){
           if (!testClass('Car')) {
          alert("Even After X seconds, Car class not loaded!");
        }else{
          alert("After X seconds, Car class loaded!");
        } 

  }, 3000);

And this url (http://m.uploadedit.com/bbtc/1572125047736.txt) contains a simple class:

class Car {
  constructor(brand) {
    this.carname = brand;
  }
  get cnam() {
    return this.carname;
  }
  set cnam(x) {
    this.carname = x;
  }
}
NVRM
  • 11,480
  • 1
  • 88
  • 87
JavaSheriff
  • 7,074
  • 20
  • 89
  • 159

2 Answers2

1

Inserting a script dynamically like you are runs the script asynchronously so you are checking for the loaded class BEFORE the dynamically loaded script has finished loading and then executed.

You can use script.onload to find out when the script has finished loading and THEN check to see if your class is present in that callback.

In addition, class constructors are not added to the window object so you have to change how you test for its existence as shown below.

var head = document.getElementsByTagName('head')[0];

var script = document.createElement('script');
script.src = 'http://m.uploadedit.com/bbtc/1572125047736.txt';
script.type = 'text/javascript';
script.onload = function() {
    if (typeof Car === "function") {
        alert("Car class loaded!");
    } else {
         alert("Car class not loaded!");
    }
}

head.append(script);

Working demo here: http://jsfiddle.net/v6hay9nb/4/


If you want to be able store the class name you're testing for in a variable, you can do it like this:

function testClass(cls) {
  return eval("typeof " + cls + " === 'function'");
}

var head = document.getElementsByTagName('head')[0];

var script = document.createElement('script');
script.src = 'http://m.uploadedit.com/bbtc/1572125047736.txt';
script.type = 'text/javascript';
script.onload = function() {
  let cls = "Car"
  if (testClass(cls)) {
    alert("Car class loaded!");
  } else {
    alert("Car class not loaded!");
  }
}

head.append(script);

Working demo here: http://jsfiddle.net/jfriend00/9q7yo645/4/

Note: These working demos have to be accessed via http:// because they are trying to load a script provided by the OP that is only available http://. As such, they can't be shown here as stackoverflow snippets (which require https:// for script resources). That's why they're using jsFiddle demos.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 1
    @user648026 - In Chrome, your jsFiddle shows this error: "(index):48 Mixed Content: The page at 'https://jsfiddle.net/' was loaded over HTTPS, but requested an insecure script 'http://m.uploadedit.com/bbtc/1572125047736.txt'. This request has been blocked; the content must be served over HTTPS." – jfriend00 Oct 27 '19 at 17:24
  • 1
    @user648026 - There's another problem with your script. Declared `class` are NOT put on the `window` object. They are available in the global scope in the browser, but not on the `window` object. I've modified my code to change the test for `Car` being loaded and it now works. – jfriend00 Oct 27 '19 at 17:46
  • 1
    @user648026 - OK, you didn't make that part of the question. The only way I know of to test for that when all you have is a string would involve `eval()` or `new Function()`. You'd construct the `typeof` code (inserting the dynamic class name) into some code you build and then `eval()` it. Or change the scheme in your imported files to add the class name manually as a property to a known global symbol such as `myClasses` and then you would use `if (typeof myClasses[someClassName] === "function")` in the string you `eval()` to run the test. – jfriend00 Oct 28 '19 at 02:26
  • Thank you jfriend. I mentioned it in the title... "Dynamically load class and check if it was loaded" – JavaSheriff Oct 30 '19 at 17:24
  • 1
    @user648026 - Dynamically load, yes. You didn't say the name you were checking for was not known. Anyway, I think you'll have to use `eval()` unless you have the dynamically loaded code assign the class to a known global. Then, you can check the property on that global. – jfriend00 Oct 30 '19 at 18:17
  • I added setTimeout to the question because it might be a timing issue, can you take a look at the script now? – JavaSheriff Nov 01 '19 at 15:59
  • 1
    @user648026 - I don't understand what problem you're still working on. The timer does nothing. Your snippet in your question doesn't work for two reasons: 1) `window['Car']` is never going to work for a `class` as class names are not put on the Window object and 2), your snippet has an https problem. The snippet environment is forcing your URL to `https://m.uploadedit.com/bbtc/1572125047736.txt` which does not work. I don't know what else you want from me. I've told you what the problem is. – jfriend00 Nov 01 '19 at 18:24
  • 1
    This jsFiddle works: http://jsfiddle.net/v6hay9nb/4/. Note, you have to be running the `http://` version of this jsFiddle so it is compatible with your `http://m.uploadedit.com/bbtc/1572125047736.txt` script file. – jfriend00 Nov 01 '19 at 18:27
  • this will not work, as it hard coded, thank you anyway, – JavaSheriff Nov 01 '19 at 21:10
  • 1
    @user648026 - then change your question to show where the class name comes from. – jfriend00 Nov 01 '19 at 21:12
  • its in the question typeof window['Car'] Car is the class name, the apostrophe enclose it represent it as a string :) – JavaSheriff Nov 01 '19 at 21:21
  • 1
    @user648026 - that's not dynamic. That's hard coded at the time you wrote the code. Use a variable and show where it came from if it's actually dynamic. – jfriend00 Nov 01 '19 at 21:56
  • 1
    @user648026 - I took one more shot in my answer and can now test for a class name that's in a variable. This is what I advised you several days ago (using `eval()` to test for the existence of a top level class name). I've now implemented the code for you and given you a working demo. If this isn't what you want, you will have to edit your question to clarify what you actually want before I will consider investing any more time in it. – jfriend00 Nov 01 '19 at 22:40
  • 1
    @user648026 - Does this answer your question? – jfriend00 Nov 04 '19 at 16:09
  • It seems to work on script.onload , but not on setTimeout see here? https://jsfiddle.net/c2ap80ts/ – JavaSheriff Nov 04 '19 at 22:06
  • 1
    @user648026 - You need to be looking in the console to see errors. Your jsFiddle has the same error you had earlier. Your script is not loading because it's http in and https page (which is not allowed). Also, please don't put up an `alert()` BEFORE the event you're interested in because that completely changes the timing of things in your page. When you switch that jsFiddle to http, it works just fine: http://jsfiddle.net/jfriend00/ujk0c4bt/. I also removed the first `alert()` so it doesn't affect the test one way or the other. – jfriend00 Nov 04 '19 at 22:43
  • 1
    @user648026 - FYI, you should never be using a timer to determine when you think scripts are loaded as that's an inexact science. Use events generated from the loading process to know when the script is loaded. – jfriend00 Nov 04 '19 at 22:46
  • 1
    @user648026 - I've been trying to work with you here in time for the bounty you set up, but I can't really tell if you're done now or not logging into the site any more or have more questions. – jfriend00 Nov 05 '19 at 19:43
  • I see last link is working (http://jsfiddle.net/jfriend00/ujk0c4bt/) I accepted your solution, thank you very much for helping on this, I really appreciate this!!! – JavaSheriff Nov 05 '19 at 21:39
1

Four things! Your code might be ok, this is more server related.


Your file is of mime type text/plain. It should be text/javascript or application/javascript.

curl -I  "http://m.uploadedit.com/bbtc/1572125047736.txt"

HTTP/1.1 200 OK

Content-Length: 162

Content-Type: text/plain

Last-Modified: Sat, 26 Oct 2019 21:24:07 GMT


Your file is served over http and not https. Browsers might block while your page is served as https with the error blocked mixed content!

If your website delivers HTTPS pages, all active mixed content delivered via HTTP on this pages will be blocked by default. Consequently, your website may appear broken to users


Your file doesn't offer a CORS header. If your page is running on https, your browser is blocking:

fetch("http://m.uploadedit.com/bbtc/1572125047736.txt")

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://m.uploadedit.com/bbtc/1572125047736.txt. (Reason: CORS request did not succeed).

Test CORS online


Dynamic module import landed in Firefox 67+!

(async () => {
   await import('//.../synth/BubbleSynth.js')
})()

With error handling:

(async () => {
    await import('//.../synth/BubbleSynth.js').catch((error) => console.log('Loading failed' + error))
})()

https://caniuse.com/#feat=es6-module-dynamic-import

NVRM
  • 11,480
  • 1
  • 88
  • 87
  • Not sure why you mention CORs and `fetch()`. The OP is using a ` – jfriend00 Nov 05 '19 at 19:41