AngularJSでURLの投稿に自動でリンクを貼るようにする(ハッカー養成塾 第5回)

squareハッカー塾の次のAngularJSのタスクです。投稿にURLが含まれた場合、そのURLに自動でリンクを貼るようにするタスクです。

どうやれば実装できそうか

とりあえずググる

例のごとくとりあえずググります。[AngularJS]URLを自動的にリンクにするというドンピシャな記事が出てきました。さすがグーグル先生です。

linkyフィルタを使えばいけそうだ

公式ドキュメントを見ると、http/https/ftp/mailtoとかを見つけたらHTMLリンクを貼るよっていう機能っぽい。もうこれですね。多分。

linkyフィルタはSanitizeモジュールに含まれている機能らしい

SanitizeというのはIT用語辞典によると

Webサイトの入力フォームへの入力データから、HTMLタグ、JavaScript、SQL文などを検出し、それらを他の文字列に置き換える操作のこと。「無害化」とも呼ばれ、サニタイジング操作により、入力データ中に含まれる悪意のあるHTMLタグ、JavaScript、SQL文などが解釈・実行されることを防ぐ。

この機能をAngularJSで実装する際にSanitizeモジュールを使うというわけですね。

課題アプリの中にモジュールは読み込まれているか

script(src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular-sanitize.min.js")

ちゃんと<head>内にありますね。すでにモジュールは読み込まれているので、あとはlinkyのフィルタをかけるだけ。

 ハマる

ちょっと色々ハマったんですが、何故ハマったかが分からなくなってしまって混乱中。

ngBindHtmlディレクティブを使う

linkyフィルタの具体的な使い方は<要素 ng-bind-html=”hogehoge | linky”></要素>のように指定します。ちょっと僕もまだ理解しきれておらず、うまく説明できないのですが、ng-bind-htmlの中身は要はJavascriptなので、{{hogehoge | linky}}みたいなAngularマークアップは使いません。
これを実行するとhogehogeの中身が要素内に出力され、URLがあれば自動でリンクが貼られます。

書いてみる

.list-group-item(ng-repeat="post in posts")
  span(ng-bind-html="post.message | linky")
  span ({{post.from.name}}) {{post.created_time|date:short}}

こういうことですね。書き方すごく迷ったんですが結局linkyは要素内にフィルタをかけないといけないので投稿とそれ以外をたちまち<span>で分けてみました。出力されるソースも見てみましょう。

<div ng-repeat="post in posts" class="list-group-item ng-scope">
<span ng-bind-html="post.message | linky" class="ng-binding">
test <a href="https://mtane0412.com">https://mtane0412.com</a>
</span>
<span class="ng-binding">(種延 真之) Jan 31, 2015</span>
</div>

test https://mtane0412.comという投稿はこのように出力されました。きっちり動作してますね。なんで空要素なんだろうなぁと思ったんですが、要素内に出力してる感じなのかな。今回はなぜかかなり苦戦しました。

次回はいよいよハードにJavascriptを扱っていくのでまたもやかなり苦戦しそうです。がんばろう・・・。