AngularJS:ng-include内でAngular Loadスクリプトを作成するにはどうすればよいですか?


85

ねえ、私は角度のあるウェブページを構築しています。問題は、角度のないものがすでに構築されていることであり、それらも含める必要があります

問題はこれです。

main.htmlに次のようなものがあります。

<ngInclude src="partial.html">
</ngInclude>

そして私のpartial.htmlはこのようなものを持っています

<h2> heading 1 <h2>
<script type="text/javascript" src="static/js/partial.js">
</script>

そして、私のpartial.jsはangularjsとは何の関係もありません。ngincludeは機能し、htmlは表示されますが、ロードされているjavascriptファイルがまったく表示されません。firebug / chrome-dev-toolの使い方は知っていますが、ネットワークリクエストが行われているのを見ることができません。私は何が間違っているのですか?

私はAngularがスクリプトタグに特別な意味を持っていることを知っています。オーバーライドできますか?

回答:


101

受け入れられた回答は、1.2.0-rc1 +(Githubの問題)からは機能しません。

これがエンドラマによって作成された簡単な修正です:

/*global angular */
(function (ng) {
  'use strict';

  var app = ng.module('ngLoadScript', []);

  app.directive('script', function() {
    return {
      restrict: 'E',
      scope: false,
      link: function(scope, elem, attr) {
        if (attr.type === 'text/javascript-lazy') {
          var code = elem.text();
          var f = new Function(code);
          f();
        }
      }
    };
  });

}(angular));

このファイルを追加し、ngLoadScriptモジュールをアプリケーションの依存関係type="text/javascript-lazy"としてロードし、部分的に遅延ロードするスクリプトの型として使用するだけです。

<script type="text/javascript-lazy">
  console.log("It works!");
</script>

5
スクリプトタグにインラインjsではなくsrc属性がある場合、これは機能しないと思います。
blaskovicz 2014

9
@Blaskoviczこれを試してください:gist.github.com/subudeepak/9617483#file-angular-loadscript-js
Paolo Moretti

1
これは完全に機能しますが、もう1つ必要なことがあります。ディレクティブが破棄されたら、これを削除するにはどうすればよいですか?
SLearner 2014

レイジースクリプトでコントローラーを宣言すると、ビューでコントローラーを参照するとエラーが発生しました。なぜなのかご存知ですか?
Changwang Zhang

それがトリックでした。パーシャルにロードされたタブセットのタブ初期化コードを実行するために使用しました
LKallipo 2016年

39

簡単な答え:AngularJS( "jqlite")はこれをサポートしていません。(Angularを含める前に)ページにjQueryを含めると、機能するはずです。https://groups.google.com/d/topic/angular/H4haaMePJU0/discussionを参照してください


2
partial.jsにコントローラーが含まれている場合、これはどのように機能しますか?テンプレートは、コントローラーがロードされる前にレンダリングされ、エラーが発生します。引数 'MyController'は関数ではなく、未定義になっています。
sthomps 2013年

2
@sthomps、これが役立つかどうかを確認してください:コントローラーを動的にロードする
Mark Rajcok 2013年

16
これが機能する理由がわかりません-ブラウザは挿入されたスクリプトタグを自動的にロードしませんか?これがjQueryまたはjqLit​​eの懸念事項であるのはなぜですか?
スコットコーツ

私にとってもうまくいきました。私の<script>タグの内容はangularjsとは無関係でした。私がangularjsの前にjQueryをロードしなかったとき、以下の部分的なスクリプトタグを含むすべてが削除され、非常に奇妙でした。
ニックラスラー2015年

20

neemzyのアプローチを試しましたが、1.2.0-rc.3を使用しても機能しませんでした。スクリプトタグはDOMに挿入されますが、JavaScriptパスは読み込まれません。ロードしようとしたJavaScriptが別のドメイン/プロトコルからのものだったためだと思います。だから私は別のアプローチを取りました、そしてこれは私が例としてグーグルマップを使って思いついたものです:(要点

angular.module('testApp', []).
    directive('lazyLoad', ['$window', '$q', function ($window, $q) {
        function load_script() {
            var s = document.createElement('script'); // use global document since Angular's $document is weak
            s.src = 'https://maps.googleapis.com/maps/api/js?sensor=false&callback=initialize';
            document.body.appendChild(s);
        }
        function lazyLoadApi(key) {
            var deferred = $q.defer();
            $window.initialize = function () {
                deferred.resolve();
            };
            // thanks to Emil Stenström: http://friendlybit.com/js/lazy-loading-asyncronous-javascript/
            if ($window.attachEvent) {  
                $window.attachEvent('onload', load_script); 
            } else {
                $window.addEventListener('load', load_script, false);
            }
            return deferred.promise;
        }
        return {
            restrict: 'E',
            link: function (scope, element, attrs) { // function content is optional
            // in this example, it shows how and when the promises are resolved
                if ($window.google && $window.google.maps) {
                    console.log('gmaps already loaded');
                } else {
                    lazyLoadApi().then(function () {
                        console.log('promise resolved');
                        if ($window.google && $window.google.maps) {
                            console.log('gmaps loaded');
                        } else {
                            console.log('gmaps not loaded');
                        }
                    }, function () {
                        console.log('promise rejected');
                    });
                }
            }
        };
    }]);

誰かのお役に立てば幸いです。


4
奇妙なことに、私は外部スクリプトを使用して1.2.0-rc3で独自のバージョンを作成しました:)とにかく、これを共有してくれてありがとう、あなたのバージョンはずっと良くなっています!
neemzy 2013年

12

このメソッドを使用して、スクリプトファイルを動的に(コントローラー内で)ロードしました。

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "https://maps.googleapis.com/maps/api/js";
document.body.appendChild(script);

ナイスワン@ azmeer–
Ali

動的なスクリプト読み込みのためのシンプルで最良のソリューションであるため、投票されました。
RLD 2018

8

これは、1.2.0-rc1からは機能しなくなります。詳細については、この問題を参照しください。ここでは、簡単な回避策を説明するコメントを投稿しました。ここでも共有します:

// Quick fix : replace the script tag you want to load by a <div load-script></div>.
// Then write a loadScript directive that creates your script tag and appends it to your div.
// Took me one minute.

// This means that in your view, instead of :
<script src="/path/to/my/file.js"></script>

// You'll have :
<div ng-load-script></div>

// And then write a directive like :
angular.module('myModule', []).directive('loadScript', [function() {
    return function(scope, element, attrs) {
        angular.element('<script src="/path/to/my/file.js"></script>').appendTo(element);
    }
}]);

これまでで最高のソリューションではありませんが、スクリプトタグを後続のビューに配置することもできません。私の場合、これはFacebook / Twitter / etcを使用するために行う必要があります。ウィジェット。


4

ocLazyLoadを使用すると、ルーター(ui-routerなど)を介してテンプレート/ビューにスクリプトを遅延ロードできます。これがスニプレットです

$stateProvider.state('parent', {
    url: "/",
    resolve: {
        loadMyService: ['$ocLazyLoad', function($ocLazyLoad) {
             return $ocLazyLoad.load('js/ServiceTest.js');
        }]
    }
})
.state('parent.child', {
    resolve: {
        test: ['loadMyService', '$ServiceTest', function(loadMyService, $ServiceTest) {
            // you can use your service
            $ServiceTest.doSomething();
        }]
    }
});  

私はこのような同じ問題に直面しました。企業のアプリで、あなたはその優れたタブを持つと-含めるngの使用するように、すべてのあなたのルートを使用する必要がありますが、含まngのは、それが何の依存関係のロード機能を持っていないですウィッヒその問題..持っている
Serak Shiferaw

1

からrecaptchaを動的にロードするui-viewには、次の方法を使用します。

application.js

    .directive('script', function($parse, $rootScope, $compile) {
    return {
        restrict: 'E',
        terminal: true,
        link: function(scope, element, attr) {
            if (attr.ngSrc) {
                 var domElem = '<script src="'+attr.ngSrc+'" async defer></script>';
                 $(element).append($compile(domElem)(scope));


            }
        }
    };
});

myPartial.client.view.html

 <script type="application/javascript" ng-src="http://www.google.com/recaptcha/api.js?render=explicit&onload=vcRecaptchaApiLoaded"></script>

それはAngularネイティブスクリプトディレクティブに追加またはオーバーライドしますか?そして、それはjqueryを使用していますか?
jamie 2016年

1
に追加します。いいえ、そこではJqueryは使用されていません
Michael Draper

thx- 'ここではjQueryは使用されて$(element)いません' -weird-なぜ$()構文が必要なのですか。ajsdocsから'Angularのすべての要素参照は常にjQueryまたはjqLit​​eでラップされます'(ディレクティブのコンパイル/リンク関数の要素引数など) -それと私の他の経験から-私はあなたが '要素を使用することを期待していました。 append(...) `-最終的には使用できるものではありませんでしたが-テストすると、その部分を見て混乱し、「element.append」だけを使用してみたときに機能しませんでした構文
jamie 2016年

はい、そうですが、必要に応じて、angular.element()に置き換えることができます。
Michael Draper

0

残念ながら、この投稿のすべての答えは私にはうまくいきませんでした。次のエラーが発生し続けました。

「ドキュメント」で「書き込み」を実行できませんでした:明示的に開かない限り、非同期でロードされた外部スクリプトからドキュメントに書き込むことはできません。

これは、追加の外部JavaScriptファイルを呼び出してHTMLを挿入しようとするサードパーティのウィジェット(私の場合はdemandforce)を使用した場合に発生することがわかりました。コンソールとJavaScriptコードを見ると、次のような複数の行に気づきました。

document.write("<script type='text/javascript' "..."'></script>");

https://github.com/krux/postscribeからサードパーティのJavaScriptファイル(htmlParser.jsおよびpostscribe.js)を使用しました。これでこの投稿の問題が解決し、同時に上記のエラーが修正されました。

(これは、現在の厳しい締め切りの下での迅速で汚い方法でした。ただし、サードパーティのJavaScriptライブラリを使用することに慣れていません。誰かがよりクリーンでより良い方法を考え出すことができるといいのですが。)


0

GooglereCAPTCHAを明示的に使用してみました。次に例を示します。

// put somewhere in your index.html
<script type="text/javascript">
var onloadCallback = function() {
  grecaptcha.render('your-recaptcha-element', {
    'sitekey' : '6Ldcfv8SAAAAAB1DwJTM6T7qcJhVqhqtss_HzS3z'
  });
};

//link function of Angularjs directive
link: function (scope, element, attrs) {
  ...
  var domElem = '<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>';
  $('#your-recaptcha-element').append($compile(domElem)(scope));
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.