web-dev-qa-db-fra.com

Angular angulaire templateUrl relative au fichier .js

Je construis une directive angular angulaire qui sera utilisée dans différents emplacements. Je ne peux pas toujours garantir la structure de fichier de l'application dans laquelle la directive est utilisée, mais je peux forcer l'utilisateur mettre le directive.js et directive.html (pas les noms de fichiers réels) dans le même dossier.

Lorsque la page évalue le directive.js, il considère que templateUrl est relatif à lui-même. Est-il possible de définir le templateUrl pour qu'il soit relatif au directive.js fichier?

Ou est-il recommandé d'inclure simplement le modèle dans la directive elle-même.

Je pense que je peux vouloir charger différents modèles en fonction des circonstances, je préférerais donc pouvoir utiliser un chemin relatif plutôt que de mettre à jour le directive.js

85
pedalpete

Le fichier de script en cours d'exécution sera toujours le dernier du tableau scripts, vous pourrez donc trouver facilement son chemin:

// directive.js

var scripts = document.getElementsByTagName("script")
var currentScriptPath = scripts[scripts.length-1].src;

angular.module('app', [])
    .directive('test', function () {
        return {
            templateUrl: currentScriptPath.replace('directive.js', 'directive.html')
        };
    });

Si vous ne savez pas quel est le nom du script (par exemple, si vous regroupez plusieurs scripts en un), utilisez ceci:

return {
    templateUrl: currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1) 
        + 'directive.html'
};

Note: Dans les cas où une fermeture est utilisée, votre code doit être à l'extérieur pour garantir que le currentScript est évalué au moment opportun, tel que:

// directive.js

(function(currentScriptPath){
    angular.module('app', [])
        .directive('test', function () {
            return {
                templateUrl: currentScriptPath.replace('directive.js', 'directive.html')
        };
    });
})(
    (function () {
        var scripts = document.getElementsByTagName("script");
        var currentScriptPath = scripts[scripts.length - 1].src;
        return currentScriptPath;
    })()
);
76
Alon Gubkin

Comme vous avez dit que vous vouliez fournir différents modèles à des moments différents des directives, pourquoi ne pas autoriser le modèle lui-même à être transmis à la directive en tant qu'attribut?

<div my-directive my-template="template"></div>

Ensuite, utilisez quelque chose comme $compile(template)(scope) à l'intérieur de la directive.

6
Matt Way

Ce code est dans un fichier appelé routes.js

Ce qui suit n'a pas fonctionné pour moi:

var scripts = document.getElementsByTagName("script")
var currentScriptPath = scripts[scripts.length-1].src;
var baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);

ce qui suit a:

var bu2 = document.querySelector("script[src$='routes.js']");
currentScriptPath = bu2.src;
baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);

Mon test est basé sur le blog suivant relatif à l'utilisation de require to load paresseux angular: http://ify.io/lazy-loading-in-angularjs/

require.js engendre un bootstrap requireConfig

requireConfig engendre un angular app.js

app.js angulaire engendre mes routes.js

J'ai eu le même code étant servi par un framework web Revel et asp.net mvc. Dans revel, document.getElementsByTagName ("script") a généré un chemin d'accès vers mon fichier require bootstrap) et PAS mon fichier routes.js. Dans ASP.NET MVC, il a généré un chemin d'accès au lien de navigateur injecté de Visual Studio. élément de script qui est placé là pendant les sessions de débogage.

ceci est mon code de travail routes.js:

define([], function()
{
    var scripts = document.getElementsByTagName("script");
    var currentScriptPath = scripts[scripts.length-1].src;
    console.log("currentScriptPath:"+currentScriptPath);
    var baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);
    console.log("baseUrl:"+baseUrl);
    var bu2 = document.querySelector("script[src$='routes.js']");
    currentScriptPath = bu2.src;
    console.log("bu2:"+bu2);
    console.log("src:"+bu2.src);
    baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);
    console.log("baseUrl:"+baseUrl);
    return {
        defaultRoutePath: '/',
            routes: {
            '/': {
                templateUrl: baseUrl + 'views/home.html',
                dependencies: [
                    'controllers/HomeViewController',
                    'directives/app-style'
                ]
            },
            '/about/:person': {
                templateUrl: baseUrl + 'views/about.html',
                dependencies: [
                    'controllers/AboutViewController',
                    'directives/app-color'
                ]
            },
            '/contact': {
                templateUrl: baseUrl + 'views/contact.html',
                dependencies: [
                    'controllers/ContactViewController',
                    'directives/app-color',
                    'directives/app-style'
                ]
            }
        }
    };
});

Ceci est ma sortie de console lorsque vous utilisez Revel.

currentScriptPath:http://localhost:9000/public/ngApps/1/requireBootstrap.js routes.js:8
baseUrl:http://localhost:9000/public/ngApps/1/ routes.js:10
bu2:[object HTMLScriptElement] routes.js:13
src:http://localhost:9000/public/ngApps/1/routes.js routes.js:14
baseUrl:http://localhost:9000/public/ngApps/1/ 

Une autre bonne chose que j’ai faite est de tirer parti de la configuration requise et d’y ajouter des configurations personnalisées. c'est-à-dire ajouter

customConfig: { baseRouteUrl: '/AngularLazyBaseLine/Home/Content' } 

vous pouvez ensuite l'obtenir en utilisant le code suivant à l'intérieur de routes.js

var requireConfig = requirejs.s.contexts._.config;
console.log('requireConfig.customConfig.baseRouteUrl:' + requireConfig.customConfig.baseRouteUrl); 

vous avez parfois besoin de définir un début de base, parfois de le générer dynamiquement. Votre choix pour votre situation.

3
Herb Stahl

En plus de la réponse de Alon Gubkin , je suggérerais de définir une constante à l'aide d'une expression de fonction appelée immédiatement pour stocker le chemin du script et l'injecter dans la directive:

angular.module('app', [])

.constant('SCRIPT_URL', (function () {
    var scripts = document.getElementsByTagName("script");
    var scriptPath = scripts[scripts.length - 1].src;
    return scriptPath.substring(0, scriptPath.lastIndexOf('/') + 1)
})())

.directive('test', function(SCRIPT_URL) {
    return {
        restrict :    'A',
        templateUrl : SCRIPT_URL + 'directive.html'
    }
});
3
Michael Grath

Certains pourraient le suggérer légèrement "hacky", mais je pense que jusqu'à ce qu'il n'y ait qu'une seule façon de le faire, tout va être hacky.
J'ai également eu beaucoup de chance avec cela:

angular.module('ui.bootstrap', [])
  .provider('$appUrl', function(){
    this.route = function(url){
       var stack = new Error('dummy').stack.match(new RegExp(/(http(s)*\:\/\/)[^\:]+/igm));
       var app_path = stack[1];
       app_path = app_path.slice(0, app_path.lastIndexOf('App/') + 'App/'.length);
         return app_path + url;
    }
    this.$get = function(){
        return this.route;
    } 
  });

Ensuite, lorsque vous utilisez le code dans une application après avoir inclus le module dans l'application.
Dans une fonction de configuration d'application:

.config(['$routeProvider', '$appUrlProvider', function ($routeProvider, $appUrlProvider) {

    $routeProvider
        .when('/path:folder_path*', {
            controller: 'BrowseFolderCntrl',
            templateUrl: $appUrlProvider.route('views/browse-folder.html')
        });
}]);

Et dans un contrôleur d'application (si nécessaire):

var MyCntrl = function ($scope, $appUrl) {
    $scope.templateUrl = $appUrl('views/my-angular-view.html');
};

Il crée une nouvelle erreur javascript et extrait la trace de la pile. Il analyse ensuite toutes les URL (à l’exception de la ligne d’appel/du numéro de caractère).
Vous pouvez alors extraire le premier du tableau qui sera le fichier actuel dans lequel le code est exécuté.

Ceci est également utile si vous souhaitez centraliser le code puis extraire le second ([1]) dans le tableau, pour obtenir l'emplacement du fichier appelant

2
dan richardson

Comme plusieurs utilisateurs l'ont signalé, les chemins d'accès pertinents ne sont pas utiles lors de la création des fichiers statiques, et je le recommande vivement.

Il y a une fonctionnalité intéressante dans Angular appelé $ templateCache , qui cache plus ou moins les fichiers de modèle, et la prochaine fois que angular nécessite Un, au lieu de faire une demande réelle, il fournit la version mise en cache. Voici une façon typique de l’utiliser:

module = angular.module('myModule');
module.run(['$templateCache', function($templateCache) {
$templateCache.put('as/specified/in/templateurl/file.html',
    '<div>blabla</div>');
}]);
})();

De cette façon, vous abordez tous les deux le problème des URL relatives et vous gagnez en performance.

Bien sûr, nous aimons l’idée d’avoir des fichiers html de modèles séparés (contrairement à réagir), donc ce qui précède n’est pas bon en soi. Voici le système de construction, qui peut lire tous les fichiers HTML de modèle et construire un fichier js tel que ci-dessus.

Il existe plusieurs modules html2js pour grunt, gulp, webpack, et c’est l’idée principale qui les sous-tend. Personnellement, j’utilise beaucoup gulp, c’est pourquoi j’ai particulièrement envie gulp-ng-html2js car c’est très facile à faire.

0
Wtower