Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
AngularJS TIPS

AngularJS TIPS

画像を動的に生成するには?(ng-src/ng-srcset)

2016年6月6日

<img>タグのng-src属性に指定する画像リソースのURLをAngularJSのスコープオブジェクト経由で完成させることで、動的に画像を表示する方法を説明する。

  • このエントリーをはてなブックマークに追加

 以下のコードは、画像(<img>要素のsrc属性)をスコープオブジェクト経由で動的に生成する例です。ここでは、スコープオブジェクトのisbnプロパティにリテラルを設定しているだけですが、一般的には外部サービスから取得した情報を基に、画像パスを生成するような状況はよくあることです。

HTML
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8" />
<title>AngularJS TIPS</title>
</head>
<body ng-controller="MyController">
<div>
 <img src="http://www.wings.msn.to/books/{{isbn}}/{{isbn}}.jpg" />
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script>
angular.module('myApp', [])
 .controller('MyController', ['$scope',  function($scope) {
   $scope.isbn = '978-4-7741-7568-3';
 }]);
</script>
</body>
</html>
リスト1 スコープオブジェクト経由で画像のパスを設定するコード(src.html)

 このコードを実行し、ブラウザーの開発者ツールから通信状況を確認してみましょう(図1)。Chromeであれば[Network]タブから確認できます。

図1 画像取得時の通信状況(開発者ツールから確認)

 すると、最初にAngularJSによって処理される前の「http://www.wings.msn.to/books/{{isbn}}/{{isbn}}.jpg」をリクエストし、その後、あらためて本来の画像「http://www.wings.msn.to/books/978-4-7741-7568-3/978-4-7741-7568-3.jpg」をリクエストしていることが分かります。

 これは無駄なリクエストという意味で望ましい状況ではありませんし、そもそも壊れた画像、もしくは意図しない画像が(一瞬かもしれませんが)表示されるのは、ユーザーに対して誤解を招く原因にもなります。

 そこでAngularJSで画像パスを動的に作成する場合には、src属性ではなく、ng-src属性を利用するようにしてください(リスト2)。ng-src属性を利用することで、AngularJSが本来のsrc属性を生成するまでは、画像はリクエストされません。よって、余計なリクエストが発生したり、意図しない画像が表示されたりしてしまうような不具合も改善できます。

HTML
<img ng-src="http://www.wings.msn.to/books/{{isbn}}/{{isbn}}.jpg" />
リスト2 ng-src属性に書き換えたコード(src.html)
図2 余計なリクエストがなくなった(開発者ツールから確認)

[Note]ng-srcset属性

 ng-src属性とよく似た属性として、ng-srcset属性もあります。ng-srcset属性は、srcset属性のAngularJS版です。

 srcset属性はHTML5で追加された属性で、以下のように画像パスを「パス 条件」のカンマ区切りで表します。

HTML
<img src="images/sample.png"
    srcset="images/sample.png 1x,
            images/sample_high.png 2x" />
srcset属性を利用したコード

 これによって通常のデバイス(PCのディスプレイなど)ではsample.pngを、高解像度のデバイス(iPhoneのRetinaディスプレイなど)ではsample_high.pngを、それぞれ読み込むようになります(xデバイスピクセル比を表し、例えば上記の2xは「2倍」のデバイスピクセル比を持つデバイスという条件を意味します*1)。つまり、srcset属性を利用することで、解像度に応じて画像を切り替える(=レスポンシブ対応する)ような用途で、特別なコードを記述する必要がなくなるわけです。

  • *1 コード例ではsrc属性も記載されていますが、これは下位互換性のための指定です。srcset属性を利用できないブラウザーでは、src属性が優先して読み込まれます。

補足:ng-src属性ではJavaScript疑似プロトコルは使わない

 AngularJSアプリでは、ng-srcsrc属性でJavaScript疑似プロトコル(href="javascript:~")は利用できませんので、注意してください。利用した場合にもエラーにはなりませんが、以下のように自動的にサニタイズされてしまいます。

HTML
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8" />
<title>AngularJS TIPS</title>
</head>
<body ng-controller="MyController">
<div>
 <img ng-src="{{memo}}" />
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script>
angular.module('myApp', [])
 .controller('MyController', ['$scope', function($scope) {
   $scope.memo = 'JavaScript:alert("注意!")';
 }]);
</script>
</body>
</html>
リスト3 ng-src属性でJavaScript疑似プロトコルを利用したコード(src_js.html)
HTML
<img ... src='unsafe:javascript:alert("注意!")'>
JavaScript疑似プロトコルがサニタイズされた
処理対象:ディレクティブ カテゴリ:基本
処理対象:画像 カテゴリ:基本
API:ngSrcset(ng-srcset)|ngSrc(ng-src) カテゴリ:ng(コアモジュール) > directive(ディレクティブ)

※以下では、本稿の前後を合わせて5回分(第57回~第61回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

AngularJS TIPS
57. $injectorサービスでサービスの取得/存在確認を行うには?($injector)

AngularJSの管理外でサービスを手動でインスタンス化して利用できる$injectorサービスの応用的な活用方法として、has/get/instantiateメソッドを解説する。

AngularJS TIPS
58. モデルをバインドするテンプレートを指定するには?(ng-bind-template)

AngularJSのディレクティブであるng-bind-template属性を使って、{{...}}エクスプレッションを含むテンプレートをビューにバインドする方法を説明する。

AngularJS TIPS
59. 【現在、表示中】≫ 画像を動的に生成するには?(ng-src/ng-srcset)

<img>タグのng-src属性に指定する画像リソースのURLをAngularJSのスコープオブジェクト経由で完成させることで、動的に画像を表示する方法を説明する。

AngularJS TIPS
60. 不正な入力値もモデルに反映させるには?(ng-model-options)

入力フォームに検証機能を付けた場合、デフォルトでは不正値はモデルに反映されない。この制限を回避して反映させる方法を説明する。

AngularJS TIPS
61. 日付/時刻値を入力する際にタイムゾーンを加味するには?(ng-model-options)

ng-model-optionsディレクティブにtimezoneパラメーターを指定することで、タイムゾーンによる時差を加味した日時を<input>要素から取得する方法を説明する。

サイトからのお知らせ

Twitterでつぶやこう!