angular.jsのdirectiveで指定するtemplateUrlを埋める方法

はじめに

angularでdirectiveを定義する時にhtml template部分をどのように書くかというのは幾つか方法がある。 それについて、どのような時にどのような形で書けば良いかというののまとめ。

directiveのhtml template部分の書き方

angularのdirectiveのhtml template部分を記述する方法は、少し思いつくだけでも以下の様なものがある。

  • templateUrlを使わず、templateに直接html templateの文字列を書く。
  • templateUrlを使い、server側に対応したpathのweb apiを作成
  • templateUrlを使い、text/ng-templateなscriptタグを作成
  • templateUrlを使い、$templateCacheに文字列を追加

templateを直接使う

typescriptやes6(es2015)を使っているなら、文字列補間が使えるのでこれも1つの選択肢。 特に簡単なサンプルなどではこちらを使っても良いかもしれない。ただし、たぶん、productionでは使えない。

template: `<p>${name} {{vm.message}}</p>`

web apiを作成

無駄なリクエストが発生する。基本的に使ってはダメ。おしまい。

text/ng-templateなscriptタグ

text/ng-templateなscriptタグは$templateCacheに保存されるので 以下のようなscriptタグを使うというのもありかもしれない。

<script type="text/ng-template" id="/partials/myDirective.html">
<p>hai: {{vm.message}} </p>
</script>

ただ、build後のjsにはtemplateが含まれていないということになるので、libraryとしてtemplate自体も提供しようと思った場合にはこの方法はちょっと大変かもしれない。

$templateCacheに文字列を追加

angularはまずtemplateを探す際に $templateCache を見に行く。ここにhtml templateとして使う文字列を事前に格納しておいた場合にはそれが使われる。production用のbuildであるならこれが一番良いと思う。無駄なリクエストや処理が発生せず、他のところに持って行った際にも、html templateが組み込みという状態でbundleされたjsを作ることができるので。

$templateCacheに文字列を追加する方法

「$templateCacheに文字列を追加」というのが一番良いと分かったところで、実際のところ自分で直接$templateCacheをさわるということはしたくない。めんどくさすぎる。

gulp-angular-templatecacheを使う

production用のbuildをする時には、 gulp-angular-templatecache を使うのが良い。

以下の様な形で使う。

var templateCache = require('gulp-angular-templatecache');

gulp.task('default', function () {
  return gulp.src('partials/**/*.html')
    .pipe(templateCache("app-templateCache.bundle.js", {module: "myTemplate", root: "/partials", standalone: true}))
    .pipe(gulp.dest('dist'));
});
  • module -- 利用するangular moduleの名前
  • root -- 指定したtemplate urlのbase url
  • standalone -- moduleオプションで指定した名前のangular moduleを作成する

gulp-angular-templatecacheで気をつけたほうが良いこと

ただ、個人的には、gulp-angular-templatecacheを使いましょう。全部解決とはならないような気がしている。

js/typescript側のre-buildが必要になってはいけない

typescriptを使う上で型による恩恵を受けられるが、html template部分に関してはその限りではない。 html template部分でのtypoなどは何らcompile errorにならず、ブラウザ側でのruntime errorになる。 個人的にはhtml template部分での試行錯誤が結構多くなっている。

ここでそれなりにコードベースが大きくなってしまった場合に、jsコード側のbuildが必要になってはいけない。 html template側でのtypoを修正するために10数秒のbuildを待つというのはかなりストレスフル。

したがって、「html templateの修正時にjs/typescript側のbuildが必要」になってはいけない。

とは言っても、最終的に1つのファイルにする分にはwebpackなりbrowserifyで固めたbundle自体を更にconcatするなどは必要になるかも。

存在してないファイルの指定に事前に気づけるような仕組みが欲しい。

gulp-angular-templatecacheの実装自体は単純で指定したディレクトリ以下のファイルを文字列として取り出して埋め込む。 ただ、それだけのことしかしていない。

したがって、directiveの定義時に指定したtemplate pathに対応したhtmlが常に存在するというわけではない。

以下を一致させる必要がある。

  • directiveのtemplateUrlに指定したpath
  • 利用するhtml templateファイルの位置

一致していない場合には、server側にrequestが飛んでしまう。

なので、本当は「存在してないtemplate pathを指定した時に事前に気づけるような仕組み」が欲しい。

appendix

templateUrlで指定したpathに対応したtemplateファイルが存在するか調べる方法

一番楽なのはfake-angularみたいなコードを書くことかも。(WIP)

例えば、以下の様なことをする

$ fake-angular detect-template-url app.bundle.js
/partials/foo.html
/partial/bar.html
$ for i in `fake-angular detect-template-url --root=/partials app.bundle.js | `; do test -f $i || echo $i is not found; done