web-dev-qa-db-fra.com

Chargement de templateUrl relatif

J'ai essayé de trouver la meilleure façon de créer une application modulaire et évolutive angular. J'aime vraiment la structure de projets comme angular-passe-partout , angular-app , où tous les fichiers associés sont regroupés par fonctionnalité pour les partiels et les directives.

project
|-- partial
|   |-- partial.js
|   |-- partial.html
|   |-- partial.css
|   |-- partial.spec.js

Cependant, dans tous ces exemples, l'URL du modèle est chargée par rapport à l'URL de base, et non par rapport au fichier actuel:

angular.module('account', [])
.config(function($stateProvider) {
  $stateProvider.state('account', {
    url: '/account',
    templateUrl: 'main/account/account.tpl.html', // this is not very modular
    controller: 'AccountCtrl',
  });
})

Ce n'est pas très modulaire et pourrait devenir difficile à maintenir dans les grands projets. Je devrais me souvenir de changer le chemin templateUrl chaque fois que je déplaçais l'un de ces modules. Ce serait bien s'il y avait un moyen de charger le modèle par rapport au fichier actuel comme:

templateUrl: './account.tpl.html'

Y a-t-il un moyen de faire quelque chose comme ça en angulaire?

42
Danny Nelson

Je pense que vous finirez par trouver que le maintien des chemins relatifs au fichier js sera plus difficile, voire possible. Lorsque vient le temps de livrer, vous souhaiterez très probablement concaténer tous vos fichiers javascript en un seul fichier, auquel cas vous souhaiterez que les modèles soient relatifs à baseUrl. De plus, si vous récupérez les modèles via ajax, ce qui Angular le fait par défaut, sauf si vous les pré-empaquetez dans $ templateCache, vous allez certainement les vouloir par rapport à la baseUrl, donc le le serveur sait où les trouver une fois que votre fichier js a déjà été envoyé au navigateur.

Peut-être que la raison pour laquelle vous n'aimez pas les avoir par rapport à la baseUrl en cours de développement est que vous n'exécutez pas de serveur localement? Si tel est le cas, je changerais cela. Cela vous facilitera la vie, surtout si vous allez travailler avec des itinéraires. Je voudrais vérifier Grunt , il a un serveur très simple que vous pouvez exécuter localement pour imiter une configuration de production appelée Grunt Connect . Vous pouvez également extraire un projet comme Yeoman , qui fournit un environnement de développement frontal préemballé à l'aide de Grunt, vous n'avez donc pas à passer beaucoup de temps à vous installer. Le projet Angular Seed est également un bon exemple de configuration Grunt pour le développement local.

16
Charlie Martin

La meilleure façon de le faire maintenant est d'utiliser un chargeur de module comme browserify, webpack ou TypeScript. Il y en a aussi beaucoup d'autres. Étant donné que les exigences peuvent être créées à partir de l'emplacement relatif du fichier et le bonus supplémentaire de pouvoir importer des modèles via des transformations ou des chargeurs comme partialify, vous n'avez même plus besoin d'utiliser les URL de modèle. Intégrez simplement le modèle via un besoin.

Mon ancienne réponse est toujours disponible ci-dessous:

J'ai écrit un article sur exactement ce sujet et en ai parlé lors de notre Meetup local Angular. La plupart d'entre nous l'utilisons maintenant en production.

C'est assez simple tant que votre structure de fichiers est représentée efficacement dans vos modules. Voici un aperçu rapide de la solution. Le lien complet de l'article suit.

var module = angular.module('myApp.things', []);

var all = angular.module('myApp.things.all', [
    'myApp.things',
    'things.someThing',
    'things.someOtherThing',
    'things.someOtherOtherThing',
]);

module.paths = {
    root: '/path/to/this/thing/',
    partials: '/path/to/this/thing/partials/',
    sub: '/path/to/this/thing/sub/',
};

module.constant('THINGS_ROOT', module.paths.root);
module.constant('THINGS_PARTIALS', module.paths.partials);
module.constant('THINGS_SUB', module.paths.sub);

module.config(function(stateHelperProvider, THINGS_PARTIALS) {

    stateHelperProvider.setNestedState({
        name: 'things',
        url: '/things',
        templateUrl: THINGS_PARTIALS + 'things.html',
    });
});

Et puis tous les sous-modules ou modules "relatifs" ressemblent à ceci:

var module = angular.module('things.someThing', ['myApp.things']);
var parent = angular.module('myApp.things');

module.paths = {
    root: parent.paths.sub + '/someThing/',
    sub: parent.paths.sub + '/someThing/sub/',
    partials: parent.paths.sub + '/someThing/module/partials/',
};

module.constant('SOMETHING_ROOT', module.paths.root);
module.constant('SOMETHING_PARTIALS', module.paths.partials);
module.constant('SOMETHING_SUB', module.paths.sub);

module.config(function(stateHelperProvider, SOMETHING_PARTIALS) {

    stateHelperProvider.setNestedState({
        name: 'things.someThing',
        url: "/someThing",
        templateUrl: SOMETHING_PARTIALS + 'someThing.html',
    });
});

J'espère que cela t'aides!

Article complet: Modules AngularJS relatifs

À votre santé!

15
tannerlinsley

Je mâche cette question depuis un moment maintenant. J'utilise gulp pour empaqueter mes modèles pour la production, mais j'avais du mal à trouver une solution dont j'étais satisfait pour le développement.

C'est là que je me suis retrouvé. L'extrait ci-dessous permet de recâbler n'importe quelle URL comme bon vous semble.

angular.module('rm').config(function($httpProvider) {

  //this map can be defined however you like
  //one option is to loop through script tags and create it automatically
  var templateMap = {
    "relative.tpl.html":"/full/path/to/relative.tpl.html",
    etc...
  };

  //register an http interceptor to transform your template urls
  $httpProvider.interceptors.Push(function () {
    return {
      'request': function (config) {
        var url = config.url;
        config.url = templateMap[url] || url;
        return config;
      }
    };
  });
});
1
Tom Makin

Actuellement, il est possible de faire ce que vous voulez en utilisant le chargeur de modules systemJs .

import usersTemplate from './users.tpl';

var directive = {
   templateUrl: usersTemplate.name
}

Vous pouvez vérifier un bon exemple ici https://github.com/swimlane-contrib/angular1-systemjs-seed

1