Angular指令templateUrl相对于.js文件
我正在构build一个angular度指令,将在几个不同的位置使用。 我不能总是保证指令的应用程序的文件结构,但我可以强制用户把directive.js
和directive.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,因为它非常简单。