web-dev-qa-db-ja.com

AngularJSを使用して非角度のJavaScriptファイルを遅延ロードする方法は?

Angularコントローラーからプレーンな古いJSまたはAMDモジュールをロードすることは可能ですか?以前はこれにRequireJSを使用しました。

以前、かなり大きなプロジェクトでAngularJSとRequireJSを使用しました。私はMEAN Stackシードに基づく新しいプロジェクトに取り組んでおり、requireJSを使用していません。

私は完全には明確ではありませんが、Angularにはモジュールをロードするためのシステムがあります-私のangularコントローラ内から特定のJavaScriptをロードできますか?

追加の通常のJavaScriptファイルを含めるようにmodule()宣言を変更する方法はありますか?

ありがとう!

編集:私が何をしているかを少し理解するために、いくつかの異なるフォームを編集するページを持っています。これらはそれぞれ「フォーム」としてデータベースに保存されます。フォームの種類に応じて、さまざまな辞書値がさまざまなサブビューのさまざまなフィールドにマップされます。一部のフォームには、ドロップダウンや入力リストなどがあります。これらは異なりますが、「フォーム」に関する他のすべては一般的な方法で処理されます。

そのため、さまざまなフォームを処理する単一のフォームコントローラがあり、その結果に非常に満足しています。主な問題は、各フォームに個別のデータセットがあり、必要でない限りロードしたくないということです。

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をロードしたいと思います。

基本的に、選択した多くのオプションの1つに応じて、ロードしたいより大きなネームスペースがいくつかあり、それらすべてをロードするだけではコストがかかります。

16
Yablargo

わかりました、すべてを説明するようにコードにコメントしました。他にご不明な点がありましたらお知らせください。これは、コメントでさらに説明されている問題の解決策です。 ここでライブデモ(クリック)

マークアップ:

<!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は、ほとんどのことをかなり単純にします。

注:スクリプトタグの挿入はオプションですが、スクリプトを直接実行するのではなく、スクリプトを挿入することを強くお勧めします。スクリプトタグを使用すると、「スクリプト」セクションの「リソース」の下にある開発ツールを使用して、ロードされたすべてのファイルを追跡できます。

19
m59

実際、私はangularのディレクティブとモジュール式のものについてはあまり知りませんが、私の基本的な知識で、JSファイルをロードするためのいくつかのプリロード関数を作成します... loadScript関数は、メインのhtmlページに含まれている私のapp.jsで定義されています。

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");
});
9
Sooraj ER

AngularのモジュールシステムはRequireJSとは異なります。 Angularは、モジュールの定義と構成にのみ関係し、モジュールのロードには関係しません。

つまり、angularはJavaScriptをロードするためのHTTPリクエストを発行しません。<script>タグまたはrequirejsなどの別のJavaScriptローダーを使用して、自分でロードする必要があります。

さらに、angularでは、angularアプリケーションがブートストラップされる前に、すべてのモジュールをロードして構成する必要があります。これにより、 angularモジュール。

angularモジュールのより動的なロードを処理できるようにすることは、将来のリリースで計画されている機能です。

1
dtabuenc