Premise: I've found these two answers but I don't understand how I can sistematically apply it for many libraries:
Detect and log when external JavaScript or CSS resources fail to load
HTML if statement to load local JS/CSS upon CDN failure
I've an Augular 1.x application which depends on several libraries, many of them hosted on CDN or external server.
Unfortunately when the user is offline, the Internet connection doesn't work well or there is a (CDN) server problem, some libraries occasionally fail to download and hence to load.
In this case I want to show the the user a view like "there was an error. Please reload or try later".
My doubts is: Given that the library are simply loaded (some of them even asynchronously) in index.html by:
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/angular_material/0.8.2/angular material.min.css">
for css (within head) and
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.0-rc.2/angular.min.js"></script>
for JS (at the end of body)
How can I detect the down(loading) failure of even one single library? (in fact, let's say it fails to load Angular's because of connection error, the whole app won't work. but I've several mandatory libraries)
Or should I give priority to reliability(i.e. loading libraries locally) over performance (i.e. cached CDN)?
Also, I think it's important to precise that some libraries (e.g. Google Apis) can't really be downloaded or installed via Bower.
Just add an onerror handler to the tag. This can call a fallback, give the user a message etc.
Example
Using a non-existing url will here pop up an alert:
<link
onerror="alert('woa, error')"
rel="stylesheet"
href="//ajax.googleapis.com/ajax/libs/angular_material/0.8.2/angular material.min.cssx"
>
For custom function, just define a script block in the header before the link tags so you can call a custom function:
<script>
function myFunction() {alert("whaaaa.."); /* or something more meaningful */}
</script>
<link
onerror="myFunction()"
rel="stylesheet"
href="//ajax.googleapis.com/ajax/libs/angular_material/0.8.2/angular material.min.cssx"
>
What makes most sense in this case, is a feature check. Test for the existence of JS objects or JS methods to find out if a JS library has been loaded and test for the existence of certain CSS rules to find out if a CSS file has been loaded.
See this Fiddle for a demo.
See also below for the most relevant parts of the code.
How to find out whether a certain CSS rule exists :
window.CSSRuleExists = function(rule) {
var sSheetList = document.styleSheets;
for (var sSheet = 0; sSheet < sSheetList.length; sSheet++) {
var ruleList = sSheetList[sSheet].cssRules;
for (var item = 0; item < ruleList.length; item ++){
if(ruleList[item].selectorText === rule) {
return true;
}
}
}
return false;
}
How to find out whether a certain JS method exists :
window.JSFunctionExists = function(method, parent) {
parent = (typeof parent === typeof undefined) ? window : parent;
return (typeof parent[method] === 'function');
}
How to find out whether a certain JS object exists :
window.JSObjectExists = function(object, parent) {
parent = (typeof parent === typeof undefined) ? window : parent;
return (typeof parent[object] === 'object');
}
How to use these functions :
function process() {
el1.innerHTML = CSSRuleExists('button.special');
el2.innerHTML = JSFunctionExists('CSSRuleList');
el3.innerHTML = JSObjectExists('location');
}