I'd like to dynamically load a JavaScript library, say for example D3.js, with an Angular service something like this one:
function factoryD3Loading ($q, $document, $rootScope, $window) {
var d = $q.defer();
var script = $document[0].createElement('script');
script.type = 'text/javascript';
script.async = 'async';
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js';
script.onload = function () {
$rootScope.$apply(function () {
d.resolve($window.d3);
});
};
$document.find('body').append(script);
return d.promise;
}
It works great unless I load Angular with jQuery instead of letting it use its built-in jqLite by default. From what I can tell, the onload
callback is simply never invoked when Angular is using jQuery. It's definitely invoked when Angular is just using jqLite.
Here's a non-working fiddle using jQuery, and here's a working fiddle without jQuery. Note that these are identical except for whether jQuery is loaded.
So, a two-part question:
Why does usage of jQuery cause this difference in behavior?
How can this with-jQuery behavior be corrected or worked around?
As for why, my guess is that jqLite is somehow configured with the digest cycle in a way that Angular doesn't (or can't?) configure for jQuery. If that guess is accurate, this behavior seems inconsistent and strange to the point of being a bug (in Angular, that is).
As for how, I think (but haven't yet tested) that I can load jQuery after Angular and do some ugly unwrap/rewrap to "convert" jqLite objects to have jQuery's full API when I need it. I'd prefer a cleaner approach, if one exists.