Angular指令templateUrl相对于.js文件

我正在构build一个angular度指令,将在几个不同的位置使用。 我不能总是保证指令的应用程序的文件结构,但我可以强制用户把directive.jsdirective.html (不是真正的文件名)放在同一个文件夹中。

当页面评估directive.js ,它认为templateUrl是相对于它自己的。 有没有可能将templateUrl设置为相对于directive.js文件?

还是build议只在指令本身包含模板。

我想我可能要根据不同的情况加载不同的模板,所以宁愿能够使用相对path,而不是更新directive.js

当前正在执行的脚本文件将始终是脚本数组中的最后一个,因此您可以轻松find它的path:

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

如果您不确定脚本名称是什么(例如,如果您将多个脚本打包成一个脚本),请使用以下命令:

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

注意 :在使用闭包的情况下,您的代码应该在外面以确保在正确的时间对currentScript进行评估,例如:

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

正如你所说的,你想在不同的时间提供不同的模板到指令,为什么不允许模板本身作为一个属性传递给指令?

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

然后在指令中使用类似$compile(template)(scope)东西。

该代码位于一个名为routes.js的文件中

以下对我不起作用:

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

下面做了:

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

我的testing是基于以下关于使用require来延迟加载angular度的博客: http : //ify.io/lazy-loading-in-angularjs/

require.js生成一个requireConfig引导程序

requireConfig生成一个angular度的app.js

angular度app.js会导致我的routes.js

我有相同的代码正在由一个狂欢网页框架和asp.net mvc服务。 在revel document.getElementsByTagName(“脚本”)产生了一个path,我需要引导js文件,而不是我的routes.js。 在ASP.NET MVC中,它产生了一个到Visual Studio注入的Browser Link脚本元素的path,该元素在debugging会话期间放在那里。

这是我的工作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' ] } } }; }); 

这是从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/ 

我所做的另一件好事是利用requireconfiguration,并在其中添加一些自定义configuration。 即添加

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

你可以通过在routes.js中使用下面的代码来获得它

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

有时你需要预先定义一个baseurl,有时你需要dynamic生成它。 你的select你的情况。

除了来自Alon Gubkin的回答之外,我build议使用立即调用的函数expression式来定义一个常量来存储脚本的path并将其注入到指令中:

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

有些人可能会认为它有点“哈克”,但我认为,直到只有一种方法可以做到这一点,任何事情都会变得怪异。
我也有这样做的运气很多:

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

然后,在应用程序中包含模块后,在应用程序中使用代码。
在一个应用程序configurationfunction:

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

并在应用程序控制器(如果需要):

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

它创build一个新的JavaScript错误,并拉出堆栈跟踪。 然后parsing出所有的URL(不包括调用行/字符编号)。
然后,您可以将数组中的第一个作为代码正在运行的当前文件。

如果你想集中代码,然后在数组中取出第二个( [1] )来获取调用文件的位置

正如几位用户指出的那样,build立静态文件时相关的path是没有帮助的,我强烈推荐这样做。

在Angular中有一个非常漂亮的function叫做$ templateCache ,它或多或less地caching了模板文件,下一次这个angular度需要一个,而不是提供一个实际的请求来提供caching的版本。 这是一个典型的使用方法:

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

所以这样你们就可以解决相关网站的问题,并且在性能上获得成功。

当然,我们喜欢有独立的模板html文件(与反应相反)的想法,所以上述是不好的。 这里是构build系统,它可以读取所有模板html文件,并构build如上所述的js。

grunt,gulp,webpack有几个html2js模块,这是他们背后的主要思想。 我个人使用gulp ,所以我特别喜欢gulp-ng-html2js,因为它非常简单。