smooth_smoothie
smooth_smoothie

Reputation: 1343

How can I use libraries included in <script> tags from a AngularJS Controller

I am trying to use the d3 library inside my controller. From what I researched, one of the way do that is to create a directive to append the script with the attributes needed. But I am still not able to get the reference I need to the d3 library...

This is my directive

angular.module('reportCtrl', [])

.directive('myCustomer', [function() {
    return {
        link: function(scope, element, attrs) {
            </script>
            angular.element('<script src="assets/lib/d3.js"></script>').append(element);
            angular.element('<script src="assets/lib/d3.promise.js"></script>').append(element);
        }
    }
}])

In my controller, I go to use the d3 reference. But I get undefined error...I almost need to wait for this script to load. But problem is that reportCtrl is inside another "mainController" and I cannot seem to rely on app's lifecycle consistently.

This is my controller...

.controller('reportController', function($scope, $http) {

    return $http.get('/api/admin/svc_spec_file_map')
    .success(dataset => {
        var container = d3.select('div.sheet').node();
}
});

Here is the flow of what's going on...

Upvotes: 0

Views: 738

Answers (2)

georgeawg
georgeawg

Reputation: 48968

It is bizarre that you are loading these scripts from a directive as directives can be added and removed from the DOM.

It would be wiser to load them from a service:

app.service('d3Loader', function($rootElement,$q) {
    var promise;
    this.load = function() {
        promise = promise || loadD3();
        return promise;
    };
    function loadD3 () {
        var defer = $q.defer();
        var d3url = "//unpkg.com/d3/dist/d3.js"; 
        var s = document.createElement("script");
        s.onload = function(ev) {
          defer.resolve(d3);
        };
        s.onerror = function(ev) {
          defer.reject(ev)
        };
        s.src=d3url;
        $rootElement[0].appendChild(s);
        return defer.promise;
    }
})

Usage:

d3Loader.load().then(function(d3) {
    console.log(d3);
});

The DEMO on PLNKR

Upvotes: 1

Raz Buchnik
Raz Buchnik

Reputation: 8411

First approach:

Define the script src in the index.html file. You can do this before the script src of the AngularJS mechanism - modules, controllers etc.

Then you can have access to the D3 variable in all of the scripts that are coming after it.

Second approach:

If the d3 library has an extension for AngularJS you can inject this as a dependent module. You better check this.

Third approach:

using webpack you can import the D3 direct/lazy loaded to the directive you need, but using dynamic import:

import('path/to/d3').then(d3 => {
  // do something with d3.default()
})

Key point

You should think of it a simple JS: if you define the D3 variable before initing the AngularJS framework, the D3 variable will be available in any of the AngularJS app.

Upvotes: 2

Related Questions