Как Lazy загружать неугловые файлы JavaScript, используя AngularJS?
Можно ли загрузить простые старые модули JS или AMD с углового контроллера? Я ранее использовал RequireJS для этого.
Я использовал AngularJS и RequireJS в довольно большом проекте раньше. Я работаю над новым проектом, основанным на семени MEAN Stack, и в нем не используется requireJS.
Я не совсем уверен, но в Angular есть система для загрузки модулей - могу ли я загрузить определенный фрагмент javascript из моего углового контроллера?
Есть ли способ изменить мое объявление module() для включения дополнительных обычных файлов javascript?
Спасибо!
РЕДАКТИРОВАТЬ: Чтобы немного понять, что я делаю, у меня есть страница, которая редактирует несколько различных форм. Каждый из них сохраняется в моей базе данных в виде "формы". В зависимости от типа формы разные значения словаря отображаются в разные поля в разных вложенных представлениях. Некоторые из моих форм имеют, например, выпадающие списки или списки входов. Они разные, но все остальное в "форме" обрабатывается в общем виде.
Итак, у меня есть этот уникальный контроллер форм, который обрабатывает множество различных форм, и я очень доволен результатом. Основная проблема заключается в том, что у каждой формы есть отдельный набор данных, которые я хотел бы избежать, если мне не нужно их загружать.
Я могу проверить, какую форму я загружаю, проверив мой выпадающий список, который управляет моим ng-include (который загружает подчиненную форму).
В краткосрочной перспективе я только что загрузил все и создал пространства имен в рамках моих возможностей для дифференциации.
например, $scope.form1 и $scope.form2 для данных / правил, специфичных для конкретной формы. Я бы просто не стал загружать JS, которые мне не нужны.
Изменить 2: http://jsfiddle.net/HB7LU/1320/
function MyCtrl($scope) {
$scope.doSomething = function()
{
//I'm used to wrapping with e.g require('jquery..... here, can I do the same thing with angular?
alert(" I need to run a jquery function here...");
var xml = $(someblock);
};
}
Я поставил на скрипку именно то, о чем говорю. Я хочу загрузить произвольный JS в зависимости от определенных путей в моем контроллере и только тогда, когда они мне нужны.
В основном у меня есть несколько больших пространств имен, которые я хочу загрузить, в зависимости от одного из множества выбранных параметров, и было бы дорого просто загрузить их все.
3 ответа
Хорошо, я прокомментировал свой код, чтобы он все объяснил. Если у вас есть еще вопросы, просто дайте мне знать. Это решение проблем, которые более подробно описаны в ваших комментариях. Живая демо здесь (нажмите).
Разметка:
<!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());
}
}
});
Пример ленивого загруженного скрипта:
var foo = {
someFunction: function() {
return 'I am data from a lazy loaded js function!';
}
};
Существует множество способов реализовать концепцию, которую я продемонстрировал здесь. Просто подумайте, как бы вы хотели его использовать, и напишите несколько директив для его осуществления. Angular делает большинство вещей довольно простыми.
Примечание. Добавление тега script не является обязательным, но я предпочитаю это, а не выполнять скрипт напрямую. Используя тег script, вы сможете отслеживать все загруженные файлы с помощью инструментов dev в разделе "Ресурсы" в разделе "Сценарии".
На самом деле я не очень разбираюсь в директивах angular и его модульных вещах, но со своими базовыми знаниями я создаю некоторую функцию предварительной загрузки для загрузки моих JS-файлов.... Функция loadScript определена в моем app.js, который включен в основную HTML-страницу,
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;
}
внутри контроллера использовать что-то вроде этого
app.controller('myCtrl', function($scope) {
//array of things to load are saved in a JavascriptFile
loadScript("URL_To_JavascriptFile");
});
Модульная система Angular не похожа на RequireJS. Angular касается только определения модуля и его состава, но не загрузки модуля.
Это означает, что angular не будет выдавать HTTP-запрос для загрузки любого javascript, вы сами отвечаете за его загрузку, используя <script>
теги или другой загрузчик JavaScript, например requirejs.
Кроме того, angular требует, чтобы все модули были загружены и сконфигурированы до начальной загрузки приложения angular. Это затрудняет поддержку любых схем отложенной загрузки для угловых модулей.
Возможность использования Angular для более динамичной загрузки модулей планируется в будущих выпусках.