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


85

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

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

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

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


4
または、grunt-html2jsを使用してテンプレートをjsに変換し、AngularJsがテンプレートキャッシュにキャッシュすることもできます。これはangular-uiの人がすることです。
Beyers 2014年

素晴らしいアイデアBeyers、私はgrunt-html2jsについて知りませんでした。チェックしてみます。
pedalpete

回答:


76

現在実行中のスクリプトファイルは常に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')
        };
    });

スクリプト名がわからない場合(たとえば、複数のスクリプトを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;
    })()
);

2
ああ、今それはとてもクールです!残念ながら、これは私のjsファイルのパックと縮小で壊れますね。また、「現在実行中のスクリプトファイルが常に最後のもの」であるのはなぜですか?すべてのスクリプトファイルがグローバルスコープにロードされているという印象を受けました。
pedalpete

1
ブラウザが<script>タグを検出すると、ページのレンダリングを続行する前にすぐに実行されるため、グローバルスクリプトスコープでは、最後の<script>タグが常に最後のタグになります。
Alon Gubkin 2014年

1
また、これは縮小化で壊れるべきではありませんが、パッキングで壊れるべきなので、私はそれに解決策を追加しました
Alon

私はあなたが何を意味するのかわかると思います。あなたは私が単一のスクリプトタグ内のページにすべてをロードしていると仮定していました。そうではありませんが、私はそれを回避することができます。素晴らしい創造的な答えをありがとう!
pedalpete

1
スクリプトの名前を置き換えるのでpath = currentScriptPath.split("/"); path.pop(); path.push("directive.html");はなく、ファイル名に依存せず、「directive.js」、「/ directive.js」、「path / to /directive.js」をサポートします。コードゴルフ競技では、これらを1つのステートメントにまとめます(スプライスなどを使用)。
Nathan MacInnes 2015

6

ディレクティブに異なる時間に異なるテンプレートを提供したいとおっしゃったように、テンプレート自体を属性としてディレクティブに渡してみませんか?

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

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


なぜ今日MWayに通知されたのかわかりませんが、応答しなくてすみません。ディレクティブオブジェクト内に複数のテンプレートがあることを示唆していますか?次に、$compile渡されたテンプレートをメソッドにポイントしますか?$compileとにかく使わなければならないかもしれないので、それは良い提案かもしれません。
ペダルピート2014年

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

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

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

requireConfigは角度のあるapp.jsを生成します

角度のあるapp.jsがroutes.jsを生む

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

これは私の作業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を事前に定義する必要がある場合もあれば、動的に生成する必要がある場合もあります。あなたの状況のた​​めのあなたの選択。


2

少し「ハッキー」だと言う人もいるかもしれませんが、それを行う方法が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(呼び出し元の行/文字番号を除く)を解析します。
次に、コードが実行されている現在のファイルとなる配列の最初のファイルを引き出すことができます。

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


これは遅く、ハッキーで、実際に使用するのはかなり面倒ですが、イノベーションには+1です!
Nathan MacInnes 2015

私が言ったように、実際にそれを行う方法はないので、どの方法でも長所と短所があります。アプリの読み込みごとに1回だけ使用され、アプリが存在する場所を見つけるため、パフォーマンスの問題は実際には見つかりませんでした。また、実際には非常に使いやすいので、これをangularjsプロバイダーにラップする完全なコードを示していません...私の答えが更新される可能性があります。
dan richardson 2015

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.