web-dev-qa-db-fra.com

AngularJS - chargement dynamique de JS externe basé sur des routes

J'essaie de créer une application mobile simple d'une page avec plusieurs vues et un bouton suivant\retour pour contrôler chaque vue. J'utilise la bibliothèque Angular Mobile UI.

La maquette de base est la suivante:

<html>
    <head>
        <link rel="stylesheet" href="mobile-angular-ui/dist/css/mobile-angular-ui-base.min.css">
        <link rel="stylesheet" href="mobile-angular-ui/dist/css/mobile-angular-ui-desktop.min.css">

        <script src="js/angular/angular.min.js"></script>
        <script src="js/angular/angular-route.min.js"></script>
        <script src="mobile-angular-ui/dist/js/mobile-angular-ui.min.js"></script>

        <script src="app/app.js"></script>
        <script src="app/firstController.js"></script>
        <script src="app/secondController.js"></script>
        <script src="app/thirdController.js"></script>

    </head>

    <body ng-app="demo-app">
        <div ng-view></div>

        <div ng-controller="nextBackController" class="navbar navbar-app navbar-absolute-bottom">
            <div class="btn-group justified">
              <a href="#/" class="btn btn-navbar btn-icon-only"><i class="fa fa-home fa-navbar"></i></a>
              <a href="#/second" class="btn btn-navbar btn-icon-only"><i class="fa fa-list fa-navbar"></i></a>
            </div>
        </div>

    </body>


</html>

App.js est le suivant:

var app = angular.module('demo-app', [
  "ngRoute",
  "mobile-angular-ui"
]);

app.config(function($routeProvider) {
  $routeProvider.when('/', { controller: "firstController",
                             templateUrl: "views/first.html"});
  $routeProvider.when('/', { controller: "secondController",
                             templateUrl: "views/first.html"});
  $routeProvider.when('/', { controller: "thirdController",
                             templateUrl: "views/first.html"});
});

controllers = {};

controllers.nextBackController = function($scope, $rootScope) {
    //Simple controller for the next, back buttons so we just put it in app.js
};

app.controller(controllers);

firstController.js contiendra quelque chose de similaire à:

controllers.firstController = function($scope) {
    //Do our logic here!!!
};

Le problème est que si vous remarquez en haut de la page HTML que je dois charger tous les contrôleurs. Ce n'est pas évolutif. Je veux que chaque contrôleur soit dans son propre fichier JS et ne doive pas charger statiquement chacun car l'utilisateur peut même ne jamais avoir besoin de ce contrôleur. Existe-t-il un moyen de charger dynamiquement le fichier JS réel lors du changement de route? ou puis-je coller une balise de script en haut de mon "first.html", "second.html", etc.

22
user3621014

Si je comprends bien, vous devez charger des scripts spécifiques pour chaque vue? Je partage cet extrait d'un projet personnel qui utilise ocLazyLoader un plugin qui charge les modules à la demande.

var myApp = angular.module("myApp", [
"ui.router", 
"oc.lazyLoad",  
]); 

puis dans votre routage, vous pouvez charger des fichiers JS/CSS dynamiques en conséquence, dans cet exemple, je charge les dépendances du plugin UI Select

myApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {

$stateProvider

  // State
    .state('demo', {
        url: "/demo.html",
        templateUrl: "views/demo.html",
        data: {pageTitle: 'demo page title'},
        controller: "GeneralController",
        resolve: {
            deps: ['$ocLazyLoad', function($ocLazyLoad) {
                return $ocLazyLoad.load([{
                    name: 'ui.select',
 // add UI select css / js for this state
                    files: [
                        'css/ui-select/select.min.css', 
                        'js/ui-select/select.min.js'
                    ] 
                }, {
                    name: 'myApp',
                    files: [
                        'js/controllers/GeneralController.js'
                    ] 
                }]);
            }]
        }
    })
22
Raja Khoury

Si vous connaissez Grunt:

https://github.com/ericclemmons/grunt-angular-templates

Utilisez Grunt et la tâche de génération ci-dessus pour créer un .js à partir de toutes les vues. Inclure un écouteur de tâche de surveillance sur tous les fichiers html dans un répertoire de vues. Chaque fois qu'une modification est apportée à des vues partielles, une entrée "$ templateCache" est créée avec tout le code html dans le fichier et une URL pour alias le cache. Vos itinéraires pointeront vers les vues partielles de la même manière, mais les fichiers html n'ont pas besoin d'être présents. Seul le fichier .js avec les modèles. La beauté de ceci est qu'il se charge une fois et est disponible côté client pour toute la session. Cela réduit les appels http et votre trafic peut être réduit aux appels de service Web uniquement.

Voici l'exemple d'un modèle à partir du lien github, ci-dessus:

angular.module('app').run(["$templateCache", function($templateCache) {
$templateCache.put("home.html",
// contents for home.html ...
);
...
$templateCache.put("src/app/templates/button.html",
// contents for button.html
);
}]);

Si vous n'êtes pas familier avec Grunt

Vérifiez-le. C'est assez précieux pour automatiser les builds, la minification, la concaténation, le transpiling, etc ...

http://gruntjs.com/

7
Lee Duckworth

À moins que votre application ne soit ( [~ # ~] massive [~ # ~] , vous devriez VRAIMENT éviter de servir de petits fichiers js individuellement . Cela ralentira sensiblement votre application, même si vous deviez trouver un moyen de récupérer paresseusement des fichiers selon les besoins, comme vous le suggérez dans votre question.

Une bien meilleure façon de faire cela (et la manière utilisée et suggérée par l'équipe AngularJS) est d'avoir un PROCESSUS DE CONSTRUCTION (vous devez utiliser grunt pour cela) concaténer tous vos fichiers javascript et les servir comme un seul fichier app.js. De cette façon, vous pouvez maintenir une base de code organisée avec autant de fichiers js minuscules que vous le souhaitez, mais réduire la récupération de script à une seule demande.

5
Evan Drewry

Comment installer OCLazyLoad.

1. Télécharger ocLazyLoad.js ici

Il peut être trouvé dans le dossier 'dist' du dépôt git. Vous pouvez également l'installer avec bower install oclazyload Ou npm install oclazyload.

2. Ajoutez le module oc.lazyLoad à votre application:

var myApp = angular.module("MyApp", ["oc.lazyLoad"]);

3. Chargez vos fichiers JS à la demande, en fonction des itinéraires:

    myApp.controller("MyCtrl", function($ocLazyLoad){
       $ocLazyLoad.load('testModule.js');
    }});`

Avec $ocLazyLoad Vous pouvez charger angular, mais si vous voulez charger n'importe quel composant (contrôleurs/services/filtres/...) sans définir de nouveau module, c'est tout à fait possible ( assurez-vous simplement de définir ce composant dans un module existant).

Il existe plusieurs façons d'utiliser $ocLazyLoad Pour charger vos fichiers, choisissez simplement celui que vous préférez.

N'oubliez pas non plus que si vous souhaitez vous lancer et que les documents ne suffisent pas, consultez les exemples dans le dossier 'examples'!

Démarrage rapide

4
AllJs

Je ne sais pas comment cela fonctionne en angulaire standard, cependant, vous pouvez utiliser angular-ui-router:

Les contrôleurs sont instanciés selon les besoins, lorsque leurs étendues correspondantes sont créées, c'est-à-dire lorsque l'utilisateur navigue manuellement vers un état via une URL, $ stateProvider chargera le modèle correct dans la vue, puis liera le contrôleur à l'étendue du modèle.

https://github.com/angular-ui/ui-router/wiki

1
BAYELK

Je pense que la meilleure façon est d'utiliser RequireJS , comme mentionné ici Est-il logique d'utiliser Require.js avec Angular.js? C'est totalement autorisé et cela vous permettra d'atteindre ce que vous essayez.

voici un exemple de code

https://github.com/tnajdek/angular-requirejs-seed

1
bto.rdz

RequireJS peut être vraiment utile dans ce cas. Vous pouvez déclarer les dépendances de vos fichiers JS à l'aide de RequireJS.

Vous pouvez consulter this tutoriel simple.

1
Gurjaspal