Is it possible to load plain old JS or AMD modules from an Angular Controller? I have previously used RequireJS for this.
I have used AngularJS and RequireJS on a fa
Actually i don't know much about angular's directives and it's modular things, but with my basic knowledge i build some preloading function for loading my JS files.... loadScript function is defined in my app.js which is included in main html page.
function loadScript(src,callback){
var script = document.createElement("script");
script.type = "text/javascript";
if(callback)script.onload=callback;
document.getElementsByTagName("head")[0].appendChild(script);
script.src = src;
}
inside controller use something like this
app.controller('myCtrl', function($scope) {
//array of things to load are saved in a JavascriptFile
loadScript("URL_To_JavascriptFile");
});
Angular's module system is not like RequireJS. Angular only concerns itself with module definition and composition but not with module loading.
That means angular will not issue an HTTP request for loading any javascript, you are responsible for loading that yourself, by using <script>
tags or another javascript loader, like requirejs.
Furthermore, angular requires that all modules be loaded and configured before the angular application is bootstrapped. This makes it difficult to support any sort of lazy-loading schemes for angular modules.
Making angular be able to deal with more dynamic loading of modules is a featured planned for future releases.
Ok, I commented my code so that it should explain everything. If you have any further questions, just let me know. This is the solution to the issues as are further explained in your comments. Live demo here (click).
Markup:
<!DOCTYPE html>
<html ng-app="myApp" ng-controller="myCtrl">
<head>
</head>
<body>
<button ng-click="load()">Load Foo</button>
<!-- I'm using this to bootstrap the lazy loaded script -->
<section ng-repeat="item in loaded" lazy="item"></section>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
JavaScript:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
//array of things to load
$scope.lazyThings = [
{directive:'my-foo-directive', file:'foo.js'}
];
$scope.loaded = [];
$scope.load = function() {
var loadIndex = $scope.loaded.length;
if ($scope.lazyThings[loadIndex]) {
$scope.loaded.push($scope.lazyThings[loadIndex]);
}
}
});
app.factory('myService', function($http) {
return {
getJs: function(path) {
return $http.get(path).then(function(response) {
deferred.resolve(response.data);
});
}
}
});
//this adds an attribute to kick off the directive
//for whatever script was lazy loaded
app.directive('lazy', function($compile, $q, myService) {
var directiveReturn = {
restrict: 'A',
scope: {
lazy: '='
},
link: function(scope, element) {
myService.getJs(scope.lazy.file).then(function(data) {
return addScript(scope.lazy.file, data, scope);
}).then(function() {
var $span = angular.element('<span></span>').attr(scope.lazy.directive, '');
$compile($span)(scope);
element.append($span);
});
}
}
var scriptPromises = {};
function addScript(file, js, scope) {
if (!scriptPromises[file]) { //if this controller hasn't already been loaded
var deferred = $q.defer();
//cache promise)
scriptPromises[file] = deferred.promise;
//inject js into a script tag
var script = document.createElement('script');
script.src = 'data:text/javascript,' + encodeURI(js);
script.onload = function() {
//now the script is ready for use, resolve promise to add the script's directive element
scope.$apply(deferred.resolve());
};
document.body.appendChild(script);
return deferred.promise;
}
else { //this script has been loaded before
return scriptPromises[loadFile]; //return the resolved promise from cache
}
}
return directiveReturn;
});
app.directive('myFooDirective', function() {
return {
restrict: 'A',
link: function(scope, element) {
//put the logic from your lazy loaded "foo.js" script here
element.text(foo.someFunction());
}
}
});
Sample lazy loaded script:
var foo = {
someFunction: function() {
return 'I am data from a lazy loaded js function!';
}
};
There are plenty of ways that you could implement the concept I demonstrated here. Just think about how you would like to use it, and write some directives to carry it out. Angular makes most things pretty simple.
Note: Injecting the script tag is optional - but I greatly prefer that rather than executing the script directly. When using the script tag, you will be able to track all of the loaded files with the dev tools under "Resources" in the "Scripts" section.