我正在构建一个角度指令,该指令将在几个不同的位置使用。
我不能总是保证使用该指令的应用程序的文件结构,但我可以强制用户将directive.js
和directive.html
(不是真正的文件名)放在同一个文件夹中。
当页面评估directive.js
时,它会认为templateUrl
与自身相关。是否可以将templateUrl
设置为相对于directive.js
文件?
或者建议只在模板中包含模板。
我想我可能想根据不同的情况加载不同的模板,所以更愿意使用相对路径而不是更新directive.js
答案 0 :(得分:75)
当前正在执行的脚本文件将始终是scripts数组中的最后一个脚本文件,因此您可以轻松找到其路径:
// 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;
})()
);
答案 1 :(得分:6)
正如您所说,您希望在指令的不同时间提供不同的模板,为什么不允许模板本身作为属性传递给指令?
<div my-directive my-template="template"></div>
然后在指令中使用类似$compile(template)(scope)
的内容。
答案 2 :(得分:3)
此代码位于名为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);
我的测试基于以下关于使用require来延迟加载角度的博客: http://ify.io/lazy-loading-in-angularjs/
require.js会产生一个requireConfig bootstrap
requireConfig会产生一个有角度的app.js
angular app.js会产生我的routes.js
我有一个由revel web框架和asp.net mvc提供的相同代码。 陶醉 document.getElementsByTagName( “脚本”) 产生了我的require bootstrap js文件的路径,而不是我的routes.js。 在ASP.NET MVC中,它生成了Visual Studio注入的Browser Link脚本元素的路径,该脚本元素在调试会话期间放在那里。
这是我的工作路线.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/
我做的另一件好事是利用require配置并在其中添加一些自定义配置。 即添加
customConfig: { baseRouteUrl: '/AngularLazyBaseLine/Home/Content' }
然后您可以使用routes.js
中的以下代码来获取它var requireConfig = requirejs.s.contexts._.config;
console.log('requireConfig.customConfig.baseRouteUrl:' + requireConfig.customConfig.baseRouteUrl);
有时您需要预先定义baseurl,有时您需要动态生成它。根据您的情况选择。
答案 3 :(得分:3)
除了Alon Gubkin的答案之外,我建议使用立即调用的函数表达式来定义一个常量,以存储脚本的路径并将其注入指令:
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'
}
});
答案 4 :(得分:2)
有些人可能会稍微暗示一下&#34; hacky&#34;,但我认为只有一种方法可以做到这一点,任何东西都会变成黑客。
我也很幸运也是这样做的:
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;
}
});
然后在应用程序中包含模块后在应用程序中使用代码 在app config功能中:
.config(['$routeProvider', '$appUrlProvider', function ($routeProvider, $appUrlProvider) {
$routeProvider
.when('/path:folder_path*', {
controller: 'BrowseFolderCntrl',
templateUrl: $appUrlProvider.route('views/browse-folder.html')
});
}]);
在app控制器中(如果需要):
var MyCntrl = function ($scope, $appUrl) {
$scope.templateUrl = $appUrl('views/my-angular-view.html');
};
它会产生一个新的javascript错误并拉出堆栈跟踪。然后它会解析所有网址(不包括主叫行/字符编号) 然后,您可以拉出数组中的第一个,它将是运行代码的当前文件。
如果您想集中代码然后拉出数组中的第二个([1]
)以获取调用文件位置
答案 5 :(得分:0)
正如一些用户指出的那样,相关路径在构建静态文件时没有用处,我强烈建议这样做。
Angular中有一个名为$templateCache的漂亮功能,它或多或少地缓存模板文件,下次角度需要一个,而不是发出实际请求,它提供缓存版本。这是使用它的典型方法:
module = angular.module('myModule');
module.run(['$templateCache', function($templateCache) {
$templateCache.put('as/specified/in/templateurl/file.html',
'<div>blabla</div>');
}]);
})();
因此,通过这种方式,您既可以解决相对网址的问题,也可以获得性能。
当然我们喜欢单独使用模板html文件的想法(与反应相反),所以上面的内容并不好。这是构建系统,可以读取所有模板html文件并构建如上所述的js。
grunt,gulp,webpack有几个html2js模块,这是他们背后的主要思想。我个人经常使用gulp,所以我特别喜欢gulp-ng-html2js,因为它非常容易。