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


85

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

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

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

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


4
또는 grunt-html2js를 사용하여 템플릿을 js로 변환 한 다음 AngularJ가 템플릿 캐시에 캐시 할 수 있습니다. 이것이 angular-ui 사람들이하는 일입니다.
Beyers 2014 년

좋은 아이디어 Beyers, 나는 grunt-html2js에 대해 몰랐습니다. 확인하겠습니다.
pedalpete 2014 년

답변:


76

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

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

2
오, 이제 정말 멋져요! 불행히도 이것은 내 js 파일을 압축하고 축소하는 것으로 깨질 것입니다. 또한 '현재 실행중인 스크립트 파일이 항상 마지막 파일'인 이유는 무엇입니까? 나는 모든 스크립트 파일이 전역 범위로로드된다는 인상을 받았습니다.
pedalpete 2014 년

1
브라우저가 <script>태그를 발견 하면 페이지 렌더링을 계속하기 전에 즉시 실행하므로 전역 스크립트 범위에서 마지막 <script>태그는 항상 마지막 태그입니다.
Alon Gubkin 2014 년

1
또한,이 파일 축소에 휴식하지해야하지만, 내가 그에게 솔루션을 추가 한 그래서, 포장에 휴식한다
아론 Gubkin

무슨 말인지 알 것 같아요. 단일 스크립트 태그 내에서 페이지의 모든 것을로드한다고 가정했습니다. 그것은 사실이 아니지만 나는 그것을 해결할 수 있습니다. 위대하고 창의적인 답변에 감사드립니다!
pedalpete 2014 년

1
스크립트 이름을 바꾸는 대신 path = currentScriptPath.split("/"); path.pop(); path.push("directive.html");파일 이름에 대한 종속성이 없으며 "directive.js", "/directive.js"및 "path / to / directive.js"를 지원합니다. 코드 골프 대회는 이들을 하나의 문장으로 결합하는 것입니다 (splice 등 사용).
Nathan MacInnes

6

지시문에 다른 시간에 다른 템플릿을 제공하고 싶다고 말했듯이 템플릿 자체가 특성으로 지시문에 전달되도록 허용하지 않는 이유는 무엇입니까?

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

그런 다음 $compile(template)(scope)지시문 내부 와 같은 것을 사용 하십시오.


오늘 MWay 만이 사실을 알게 된 이유를 잘 모르겠습니다. 응답하지 않아서 죄송합니다. 디렉티브 객체 내에 여러 템플릿이 있다고 제안하고 있습니까? 그런 다음 $compile전달되는 템플릿을 메소드에 지정 하시겠습니까? $compile어쨌든 사용해야 할 수도 있으므로 좋은 제안이 될 수 있습니다.
pedalpete

4

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

3

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

내 테스트는 require to lazy load angular 사용에 대한 다음 블로그를 기반으로합니다. http://ify.io/lazy-loading-in-angularjs/

require.js는 requireConfig 부트 스트랩을 낳습니다.

requireConfig는 각도 app.js를 낳습니다.

각도 app.js가 내 routes.js를 낳습니다.

revel 웹 프레임 워크와 asp.net mvc에서 동일한 코드를 제공했습니다. revel document.getElementsByTagName ( "script")에서 내 routes.js가 아닌 필요한 부트 스트랩 js 파일에 대한 경로를 생성했습니다. ASP.NET MVC에서는 디버깅 세션 중에 배치되는 Visual Studio의 삽입 된 브라우저 링크 스크립트 요소에 대한 경로를 생성했습니다.

이것은 내 작업 route.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' } 

그런 다음 route.js 내부에서 다음 코드를 사용하여 가져올 수 있습니다.

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

때로는 baseurl을 미리 정의해야하고 때로는 동적으로 생성해야합니다. 상황에 맞는 선택.


2

어떤 사람들은 약간 "해키"라고 제안 할 수도 있지만, 한 가지 방법 만있을 때까지는 모든 것이 해키가 될 것이라고 생각합니다.
나는 또한 이것을하는 데 많은 운이 좋았습니다.

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

그런 다음 앱에 모듈을 포함시킨 후 애플리케이션에서 코드를 사용할 때.
앱 구성 기능에서 :

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

새로운 자바 스크립트 오류를 ​​생성하고 스택 추적을 가져옵니다. 그런 다음 모든 URL을 구문 분석합니다 (호출 회선 / 문자 번호 제외).
그런 다음 코드가 실행되는 현재 파일이 될 배열의 첫 번째 파일을 꺼낼 수 있습니다.

이는 코드를 중앙 집중화 한 다음 [1]배열에서 두 번째 ( )를 꺼내 호출 파일 위치를 가져 오는 경우에도 유용합니다.


이것은 느리고, 엉망이고, 실제로 사용하기에는 상당히 성 가실 것이지만, 혁신에는 +1입니다!
Nathan MacInnes

내가 말했듯이 실제로 할 방법이 없으므로 어떤 방법도 장단점을 가질 것입니다. 앱이있는 위치를 찾기 위해 애플리케이션로드 당 한 번만 사용되기 때문에 실제로 성능 문제를 발견하지 못했습니다. 또한 실제로 사용하기가 매우 쉽습니다.이를 angularjs 공급자로 래핑하는 전체 코드를 표시하지 않았습니다.
dan richardson

0

여러 사용자가 지적했듯이 관련 경로는 정적 파일을 빌드 할 때 도움이되지 않으므로 그렇게하는 것이 좋습니다.

Angular에는 $ templateCache 라는 멋진 기능이 있습니다.이 기능은 템플릿 파일 을 어느 정도 캐시하고 다음에 angular가 실제로 요청하는 대신 캐시 된 버전을 제공합니다. 다음은이를 사용하는 일반적인 방법입니다.

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

따라서 이러한 방식으로 상대 URL 문제를 해결하고 성능을 높일 수 있습니다.

물론 우리는 (반응과는 대조적으로) 별도의 템플릿 html 파일을 가지고 있다는 생각을 좋아하므로 위의 내용 자체는 좋지 않습니다. 여기에 모든 템플릿 html 파일을 읽고 위와 같은 js를 구성 할 수있는 빌드 시스템이 있습니다.

grunt, gulp, webpack을위한 몇 가지 html2js 모듈이 있으며 이것이 그이면의 주요 아이디어입니다. 저는 개인적 으로 gulp를 많이 사용하므로 특히 gulp-ng-html2js를 매우 쉽게 사용하기 때문에 특히 좋아 합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.