AngularJS: Wie erstelle ich ein Angular Load-Skript in ng-include?

85

Hey, ich baue eine Webseite mit eckigen. Das Problem ist, dass es bereits Dinge gibt, die ohne Winkel gebaut sind, und ich muss sie auch einbeziehen

Das Problem ist das.

Ich habe so etwas in meiner main.html:

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

Und meine partielle.html hat so etwas

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

Und meine partielle.js hat nichts mit anglejs zu tun. nginclude funktioniert und ich kann das HTML sehen, aber ich kann nicht sehen, dass die Javascript-Datei überhaupt geladen wird. Ich weiß, wie man das Firebug / Chrome-Dev-Tool verwendet, aber ich kann nicht einmal sehen, dass die Netzwerkanforderung gestellt wird. Was mache ich falsch?

Ich weiß, dass Angular eine besondere Bedeutung für das Skript-Tag hat. Kann ich es überschreiben?

Ranjith Ramachandra
quelle

Antworten:

101

Die akzeptierte Antwort funktioniert ab 1.2.0-rc1 + ( Github-Problem ) nicht mehr.

Hier ist eine schnelle Lösung, die von endorama erstellt wurde :

/*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));

Fügen Sie einfach diese Datei hinzu, laden Sie das ngLoadScriptModul als Anwendungsabhängigkeit und verwenden Sie es type="text/javascript-lazy"als Typ für das Skript, das Sie in Partials träge laden sollen:

<script type="text/javascript-lazy">
  console.log("It works!");
</script>
Paolo Moretti
quelle
5
Ich denke nicht, dass dies funktioniert, wenn Ihr Skript-Tag ein src-Attribut anstelle von Inline-js hat.
Blaskovicz
9
@Blaskovicz Versuchen Sie dieses: gist.github.com/subudeepak/9617483#file-angular-loadscript-js
Paolo Moretti
1
Das funktioniert perfekt, aber ich möchte noch etwas. Wie entferne ich das, nachdem die Richtlinie zerstört wurde?
SLearner
Wenn ich den Controller im Lazy Script deklariere, wird beim Verweisen auf den Controller in der Ansicht eine Fehlermeldung angezeigt. Weißt du, warum?
Changwang Zhang
Das hat funktioniert. Ich habe es verwendet, um den Tab-Initialisierungscode für ein Tabset auszuführen, das im Teil geladen wurde
LKallipo
39

Kurze Antwort: AngularJS ("jqlite") unterstützt dies nicht. Fügen Sie jQuery in Ihre Seite ein (bevor Sie Angular einfügen), und es sollte funktionieren. Siehe https://groups.google.com/d/topic/angular/H4haaMePJU0/discussion

Mark Rajcok
quelle
2
Wie funktioniert das, wenn Ihre partielle.js einen Controller enthält? Die Vorlage wird gerendert, bevor der Controller geladen wird, und gibt einen Fehler aus: Das Argument 'MyController' ist keine Funktion, wurde undefiniert.
Sthomps
2
@sthomps, sehen Sie, ob dies hilft: Laden eines Controllers dynamisch
Mark Rajcok
16
Ich verstehe nicht, warum dies funktioniert - lädt der Browser nicht automatisch ein injiziertes Skript-Tag? Warum ist dies ein jQuery- oder jqLite-Problem?
Scott Coates
funktionierte auch für mich, der Inhalt meines <script> -Tags war angularjs unabhängig. Als ich jQuery nicht vor anglejs geladen habe, wurde alles in meinem Teil unten und einschließlich des Skript-Tags entfernt, sehr seltsam.
Nick Russler
20

Ich habe neemzys Ansatz ausprobiert, aber er hat bei mir mit 1.2.0-rc.3 nicht funktioniert. Das Skript-Tag würde in das DOM eingefügt, aber der Javascript-Pfad würde nicht geladen. Ich vermute, es lag daran, dass das Javascript, das ich laden wollte, aus einer anderen Domäne / einem anderen Protokoll stammte. Also habe ich einen anderen Ansatz gewählt, und das habe ich mir am Beispiel von Google Maps ausgedacht : ( Gist )

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');
                    });
                }
            }
        };
    }]);

Ich hoffe es ist hilfreich für jemanden.

Neil S.
quelle
4
Seltsam, ich habe meine eigene Version auf 1.2.0-rc3 mit externen Skripten erstellt :) Ihre Version ist sowieso viel besser, danke, dass Sie diese geteilt haben!
neemzy
10

Ich habe diese Methode verwendet, um eine Skriptdatei dynamisch (innerhalb eines Controllers) zu laden.

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "https://maps.googleapis.com/maps/api/js";
document.body.appendChild(script);
Azmeer
quelle
nice one @azmeer
Ali
Abgestimmt, weil es eine einfache und beste Lösung für das dynamische Laden von Skripten ist.
RLD
8

Ab 1.2.0-rc1 funktioniert das nicht mehr. Weitere Informationen finden Sie in dieser Ausgabe , in der ich einen Kommentar veröffentlicht habe, der eine schnelle Problemumgehung beschreibt. Ich werde es auch hier teilen:

// 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);
    }
}]);

Nicht die beste Lösung aller Zeiten, aber hey, auch das Setzen von Skript-Tags in nachfolgende Ansichten. In meinem Fall muss ich dies tun, um Facebook / Twitter / etc. Zu nutzen. Widgets.

neemzy
quelle
4

Mit ocLazyLoad können Skripte über Router (z. B. UI-Router) träge in die Vorlagen / Ansichten geladen werden. Hier ist ein Sniplet

$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();
        }]
    }
});  
Neil
quelle
Ich stand vor dem gleichen Problem wie diesem. In der Enterprise-App müssen Sie alle Ihre Routen verwenden, daher ist es besser, ng-include mit Registerkarten zu verwenden, aber ng-include hat seine Probleme, da es keine Funktion zum Laden von Abhängigkeiten gibt.
Serak Shiferaw
1

Um Recaptcha dynamisch von einem zu laden, verwende ui-viewich die folgende Methode:

In 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));


            }
        }
    };
});

In myPartial.client.view.html:

 <script type="application/javascript" ng-src="http://www.google.com/recaptcha/api.js?render=explicit&onload=vcRecaptchaApiLoaded"></script>
Michael Draper
quelle
Fügt das die eckige native Skriptanweisung hinzu oder überschreibt es sie? Und nutzt das jquery?
Jamie
1
Es fügt hinzu. Und nein, dort wird kein Jquery verwendet
Michael Draper
thx - 'hier wird keine jQuery verwendet' -weird- $(element)warum brauchst du die $()Syntax ? aus den ajs-Dokumenten 'Alle Elementreferenzen in Angular werden immer mit jQuery oder jqLite umbrochen' (wie das Elementargument in der Kompilierungs- / Verknüpfungsfunktion einer Direktive) - aus diesem und meinen anderen Erfahrungen heraus hatte ich erwartet, dass Sie das Element verwenden. append (...) `- obwohl ich am Ende nicht das war, was ich verwenden konnte - beim Testen war ich verwirrt, als ich diesen Teil sah und funktionierte nicht für mich, als ich versuchte, nur mit dem 'element.append' zu arbeiten. Syntax
Jamie
doh ja, das ist es, aber Sie könnten das höchstwahrscheinlich durch angle.element () ersetzen, wenn Sie möchten.
Michael Draper
0

Leider haben alle Antworten in diesem Beitrag bei mir nicht funktioniert. Ich bekam immer wieder folgenden Fehler.

Fehler beim Ausführen von 'Schreiben' für 'Dokument': Es ist nicht möglich, aus einem asynchron geladenen externen Skript in ein Dokument zu schreiben, es sei denn, es wird explizit geöffnet.

Ich habe herausgefunden, dass dies passiert, wenn Sie Widgets von Drittanbietern (in meinem Fall Demandforce) verwenden, die auch zusätzliche externe JavaScript-Dateien aufrufen und versuchen, HTML einzufügen. Beim Betrachten der Konsole und des JavaScript-Codes fielen mir mehrere Zeilen wie folgt auf:

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

Ich habe JavaScript-Dateien von Drittanbietern (htmlParser.js und postscribe.js) verwendet von: https://github.com/krux/postscribe . Das hat das Problem in diesem Beitrag gelöst und gleichzeitig den obigen Fehler behoben.

(Dies war ein schneller und schmutziger Weg unter der engen Frist, die ich jetzt habe. Ich bin jedoch nicht mit der Verwendung der JavaScript-Bibliothek von Drittanbietern vertraut. Ich hoffe, jemand kann einen saubereren und besseren Weg finden.)

Chris
quelle
0

Ich habe versucht, Google reCAPTCHA explizit zu verwenden. Hier ist das Beispiel:

// 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));
}
Romanyu
quelle