developer tip

.js 파일에 상대적인 각도 지시문 templateUrl

optionbox 2020. 9. 17. 07:40
반응형

.js 파일에 상대적인 각도 지시문 templateUrl


저는 몇 가지 다른 위치에서 사용될 각도 지시문을 작성하고 있습니다. 지시문이 사용 된 앱의 파일 구조를 항상 보장 할 수는 없지만 사용자가 동일한 폴더에 directive.jsdirective.html(실제 파일 이름이 아님) 를 넣도록 강제 할 수 있습니다 .

페이지가를 평가할 때는 자체에 상대적인 directive.js것으로 간주합니다 templateUrl. 파일에 templateUrl상대적으로 설정할 directive.js있습니까?

또는 지시문 자체에 템플릿을 포함하는 것이 좋습니다.

다른 상황에 따라 다른 템플릿을로드하고 싶을 수 있으므로 업데이트하는 대신 상대 경로를 사용하는 것이 좋습니다. directive.js


현재 실행중인 스크립트 파일은 항상 스크립트 배열의 마지막 파일이므로 해당 경로를 쉽게 찾을 수 있습니다.

// 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)지시문 내부 와 같은 것을 사용 하십시오.


이 코드는 route.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);

My test is based on the following blog about using require to lazy load angular: http://ify.io/lazy-loading-in-angularjs/

require.js begets a requireConfig bootstrap

requireConfig begets an angular app.js

angular app.js begets my routes.js

I had the same code being served up by a revel web framework and asp.net mvc. In revel document.getElementsByTagName("script") produced a path to my require bootstrap js file and NOT my routes.js. in ASP.NET MVC it produced a path to Visual Studio's injected Browser Link script element that is put there during debugging sessions.

this is my working routes.js code:

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

This is my console output when running from 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/ 

Another nice thing I have done is to take advantage of the require config and put some custom configurations in it. i.e. add

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

you can then get it by using the following code from inside of routes.js

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

sometimes you need to define a baseurl upfront, sometimes you need to dynamically generate it. Your choice for your situation.


In addition to the answer from Alon Gubkin I'd suggest to define a constant using an Immediately-Invoked Function Expression to store the path of the script and inject it into the 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'
    }
});

Some might suggest it slightly "hacky", but I think until there is only 1 way to do it, anything is going to be hacky.
I've had a lot of luck with also doing this:

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

Then when using the code in an application after including the module in the app.
In an app config function:

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

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

And in an app controller (if required):

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

It creats a new javascript error and pulls out the stack trace. It then parses out all urls (excluding the calling line/char number).
You can then just pull out the first in the array which will be the current file where the code is running.

This is also helpful if you want to centralise the code and then pull out the second ([1]) in the array, to get the calling file location


As several users have pointed out, relevant paths are not helpful when building the static files, and I would highly recommend doing so.

There is a nifty feature in Angular called $templateCache, which more or less caches template files, and next time that angular requires one, instead of making an actual request it provides the cached version. This is a typical way to use it:

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

So in this way you both tackle the problem of relative urls and you gain in performance.

Of course we love the idea of having separate template html files (in contrast to react), so the above by its own is no good. Here comes the build system, which can read all template html files and construct a js such as the above.

There are several html2js modules for grunt, gulp, webpack, and this is the main idea behind them. I personally use gulp a lot, so I particularly fancy gulp-ng-html2js because it does exactly this very easily.

참고URL : https://stackoverflow.com/questions/21103724/angular-directive-templateurl-relative-to-js-file

반응형