相对于.js文件的Angular指令templateUrl

时间:2014-01-13 23:57:13

标签: javascript angularjs path

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

当页面评估directive.js时,它会认为templateUrl与自身相关。是否可以将templateUrl设置为相对于directive.js文件?

或者建议只在模板中包含模板。

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

6 个答案:

答案 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,因为它非常容易。