2015-09-26 いまどきのフロントエンド環境構築にいった & Polymer で HTML の bind にハマった
いまどきのフロントエンド環境構築
『いまどきのフロントエンド環境構築』に参加した。
……とは言え、もくもくと Polymer を試していただけなのだけれど。
今週は 2015-09-20 (記事は 2015-09-21) の Polymer コードラボ以来、既存の Polymer Elements を読んでみた (2015-09-22) り、動画 Polycasts を観た (2015-09-23) りと Input ばかりでここまできた。……で、ようやく Output に目を向けたというわけ。
Polymer で HTML を bind する
そして例によってハマる。
Polymer で HTML 文字列を bind しようとしてハマった。
Polymer は Mustache のような記法で property を binding できる。{{property}}
のようなイメージだ。AngularJS や Vue.js でもおなじみの記法なのでそれ自体は問題ない。例によってこの記法は HTML escape される。つまり <b>
は <b>
のように出力されて HTML ではなくただのテキストとして binding される。
今回やりたいことの中に HTML として返されたものをそのまま埋め込むというものがあった。
この HTML escape に関してはたいてい抜け道が用意してある。たとえば Mustache では {{{html}}}
とすれば HTML escape されずに出力されるし、AngularJS では $sce
で安全であるとマークして ng-bind-html
を使うし、Vue.js では v-html
を使う。だが Polymer にはない。
Polymer には HTML escape されない方法がない。なので自身で JavaScript で要素を取得して innerHTML
に設定するしかない。しかし、ここに落とし穴 (ハマりどころ) がある。
解決済みのコードを示す。
_descriptionChanged: function() {
var html = this.description;
var el = this.$.description;
Polymer.dom(el).innerHTML = html; // 落とし穴
}
this.description
はこのインスタンスの property だ。Polymer は this.$.<id>
で指定した id の要素を取得してくれる。ポイントは Polymer.dom(el)
の部分だ。
このコードは Polymer.dom(el).innerHTML
を el.innerHTML
としてもだいたい動くが問題はある。だいたいといったのは要素自体は挿入されるからだ。問題の例は <dom-module>
内の <style>
が効かないことだ。おそらく shady DOM の実装上、CSS を外部から隔離するために DOM にいろいろと細工している。なので生の DOM を変更してしまうとまずい。
解決策はさきに書いたように Polymer.dom(el)
で wrap してやる。
ぼくは Polymer.dom
の存在は知っていたのだけど、てっきり this.$.<id>
で取得できるものは既に wrap されていると思っていた。効率の都合なのかな。