84 votes

AngularJS : Comment faire pour qu'angular charge script dans ng-include ?

Je suis en train de construire une page web avec Angular. Le problème est qu'il y a des choses qui sont déjà construites sans angular et je dois les inclure aussi

Le problème est le suivant.

J'ai quelque chose comme ceci dans mon main.html :

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

Et mon partial.html a quelque chose comme ceci

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

Et mon partial.js n'a rien à voir avec angularjs. nginclude fonctionne et je peux voir le html, mais je ne vois pas du tout le fichier javascript être chargé. Je sais comment utiliser firebug/ chrome-dev-tool, mais je ne peux même pas voir la requête réseau qui est faite. Qu'est-ce que je fais de mal ?

Je sais qu'Angular a une signification spéciale pour la balise script. Puis-je la contourner ?

101voto

Paolo Moretti Points 9519

La réponse acceptée ne fonctionnera pas à partir de la version 1.2.0-rc1+ ( Numéro Github ).

Voici une solution rapide créée par endorama :

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

Il suffit d'ajouter ce fichier, de charger ngLoadScript comme dépendance de l'application et utiliser type="text/javascript-lazy" comme type de script que l'on veut charger paresseusement dans les partiels :

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

39voto

Mark Rajcok Points 85912

Réponse courte : AngularJS ("jqlite") ne supporte pas cela. Incluez jQuery dans votre page (avant d'inclure Angular), et cela devrait fonctionner. Voir https://groups.google.com/d/topic/angular/H4haaMePJU0/discussion

20voto

Neil S Points 1140

J'ai essayé l'approche de Neemzy, mais cela n'a pas fonctionné pour moi en utilisant la version 1.2.0-rc.3. La balise script serait insérée dans le DOM, mais le chemin javascript ne serait pas chargé. Je soupçonne que c'était parce que le javascript que j'essayais de charger provenait d'un domaine/protocole différent. J'ai donc adopté une approche différente, et voici ce que j'ai obtenu, en utilisant google maps comme exemple : ( 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');
                    });
                }
            }
        };
    }]);

J'espère que ça aidera quelqu'un.

8voto

neemzy Points 790

Cela ne fonctionnera plus à partir de la version 1.2.0-rc1. Voir cette question pour en savoir plus, dans lequel j'ai posté un commentaire décrivant une solution de contournement rapide. Je vais le partager ici aussi :

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

Ce n'est pas la meilleure solution, mais bon, pas plus que de mettre des balises script dans les vues suivantes. Dans mon cas, je dois le faire pour pouvoir utiliser les widgets Facebook/Twitter/etc.

0voto

Deepak Points 66

Ajouter à la réponse de Paolo Moretti

Il existe une amélioration subtile qui contribue à rendre cette solution encore meilleure. Veuillez consulter ma réponse à Pourquoi ng-scope est ajouté au javascript inline de ma vue partielle et fait que l'alerte ne fonctionne pas ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X