web-dev-qa-db-ja.com

.jsファイルに関連するAngularディレクティブtemplateUrl

いくつかの異なる場所で使用されるangularディレクティブを作成しています。ディレクティブが使用されるアプリのファイル構造を常に保証することはできませんが、ユーザーにdirective.jsdirective.html(実際のファイル名ではない)を同じフォルダーに配置することを強制できます。

ページがdirective.jsを評価するとき、templateUrlはそれ自体に関連すると見なします。 templateUrldirective.jsファイルに対して相対的に設定することは可能ですか?

または、ディレクティブ自体にテンプレートを含めることをお勧めします。

さまざまな状況に基づいてさまざまなテンプレートをロードしたいと思うので、directive.jsを更新するよりも相対パスを使用した方がよいと思います

85
pedalpete

現在実行中のスクリプトファイルは常にスクリプト配列の最後のファイルになるため、そのパスを簡単に見つけることができます。

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

スクリプト名がわからない場合(たとえば、複数のスクリプトを1つにまとめている場合)、これを使用します。

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;
    })()
);
76
Alon Gubkin

ディレクティブに異なるタイミングで異なるテンプレートを提供したいと言ったように、テンプレート自体を属性としてディレクティブに渡すことを許可しないのはなぜですか?

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

次に、ディレクティブ内で$compile(template)(scope)などを使用します。

6
Matt Way

このコードは、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 to lazy load angularの使用に関する次のブログに基づいています: http://ify.io/lazy-loading-in-angularjs/

require.jsはrequireConfigブートストラップを生成します

requireConfigはangular app.jsを生成します

angular app.jsはroutes.jsを生成します

Revel Webフレームワークとasp.net mvcによって同じコードが提供されていました。 revel document.getElementsByTagName( "script")で、routes.jsではなくrequire bootstrap jsファイルへのパスが生成されました。 ASP.NET MVCでは、デバッグセッション中に配置されるVisual Studioの挿入されたBrowser Linkスクリプト要素へのパスを生成しました。

これは私の実際の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/ 

もう1つ良いことは、require configを利用していくつかのカスタム構成を追加することです。すなわち追加

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

次に、routes.js内から次のコードを使用して取得できます

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

baseurlを事前に定義する必要がある場合と、動的に生成する必要がある場合があります。状況に応じた選択。

3
Herb Stahl

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
Michael Grath

少し「ハッキング」を提案する人もいるかもしれませんが、それを行う方法が1つになるまでは、何でもハッキングされると思います。
これを行うことで多くの運がありました:

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

新しいjavascriptエラーを作成し、スタックトレースを引き出します。次に、すべてのURL(呼び出し行/文字番号を除く)を解析します。
その後、コードが実行されている現在のファイルとなる配列の最初のものを取り出すことができます。

これは、コードを一元化し、次に配列の2番目([1])を引き出して、呼び出し元のファイルの場所を取得する場合にも役立ちます。

2
dan richardson

複数のユーザーが指摘しているように、静的ファイルを構築する際に関連するパスは役に立たないため、そうすることを強くお勧めします。

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 を使用します。

0
Wtower