AngularJSでrouteProviderで遊んでる時に、ファイルのダウンロードやら画像の直リンクやら
意図しないリンクまでルーティングに含まれてしまう問題の対処方法。
これで3時間位詰まった。。。~~おそらくBackboneJSでも通用する。~~しませんでした。
問題
下記のようなルーティングを設定した時、
ng-app内の同一ドメイン内のすべてのリンクに対してルーティング処理が行われ、
PJAXに似た動作をするようになる。
angular.module("app", ["ngRoute"])
.config([
"$routeProvider",
"$locationProvider",
function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
return $routeProvider.when("/", {
templateUrl: "/template/index.html"
})
.when("/page01", {
templateUrl: "/template/page01.html"
})
.when("/page02", {
templateUrl: "/template/page02.html"
})
.otherwise({
redirectTo: "/"
});
}
]);
上記の指定では /
/page01
/page02
へのアクセスを行った際に
所定の場所からテンプレートを取得し、ng-viewへ反映する。
ルーティングに該当しなかった場合は /
へのリクエストとしてリダイレクトして処理する。
ここで問題となるのが、公開したアプリに下記のようなファイルをダウンロードさせるためのリンクや
画像を直リンクで表示したいといったような意図で設置したリンク。
<a href="/download/hoge.zip">ダウンロードはこちら!</a>
残念ながらこの状態でリンクを設定すると、
AngularJSはリクエストをルーティングに組み込んで処理する。
実際どのように動作するかというと、
/download/hoge.zip
をクエリとしてルーティングのマッチングを行う。
当然 router.js
の内容に該当するルートはないので、/
と同じ内容が表示されてしまう。
かと言ってroute.js
のotherwiseを外したところで内容の取得ができなくなるだけなので
リンクをクリックするとng-viewは空になる。
どうすりゃええのん(´・ω・`)
解決方法
このような場合には下記のように、ルーティングをしてほしくないURLに対して
target
を付加することで解決することができる。
例えばファイルのダウンロードのリンクは下記のようになる。
<a href="/download/hoge.zip" target="_self">ダウンロードはこちら!</a>
また応用として、ルーティングに定義済みのURLでもtarget
を付加すると
AngularJSのルーティング処理を意図して解除することができる。
<!-- こっちはルーティングされる -->
<a href="/page01">PAGE01へ</a>
<!-- こっちはルーティングされずにページの更新がかかる -->
<a href="/page02" target="_self">PAGE02へ</a>
今回は同一ページ内で処理したかったのでtarget="_self"
を指定したが
もちろん新規ウィンドウで表示したいときはtarget="_blank"
などを使うこともできる。
参考
-
Bypass AngularJS router for some <a> tags
https://coderwall.com/p/em4vua -
File download links with angulars UI-Router
http://stackoverflow.com/questions/17253903/file-download-links-with-angulars-ui-router