Goalist Developers Blog

JSでファイルダウンロードを実行したい場合はどうしたらいい?

一般的に、ファイルダウンロードのために

<a href="https://example.com/my_file.txt" download>click</a>

的なコードで行ってると思いますが、たまにリンクが事前に分からない状態であり、ボタンをクリックした後でリンクを作成してからダウンロードを実行する時もあります。その場合、サーバーが返してくれるリンクのダウンロード実行をjavascriptで行って欲しい時もあるかと思います。

普通のやり方

ほとんどの時、

document.location.assign(url);

window.open(url, '_self');

と書いて、実行できるかと思います。ただし、ファイルの種類によってブラウザーに怒られる可能性もあります。 この間まさに、

f:id:c-pattamada:20180517113207p:plain

と怒られました。 つまり、「本当のファイルがzipなのに、なんでtext扱いしてるの?!」と。 ただのワーニングなのです。でも解決があるかどうか、を調べて見ました。

まずは、

window.open(url, '_blank')

はどうでしょうか?

f:id:c-pattamada:20180517113225p:plain

確かにな、サイトが勝手に何かをダウンロードして欲しくないよね、と思いました。javascriptはそういうことのためにもいっぱい使われてますね。納得。

ですが、一方にあるポップアップブロッカーの存在すら気づいてないお客さんもいるらしい。ダウンロード期待してるのに、何も起こらなくて困ってて問い合わせが頻繁にくるというのが聞きましたので、このままじゃダメだねと思いました。

ということで、ポップアップブロッカーのCMを作りました。 違います。

元のワーニングありの状態に戻すか、別な方法を探すかという二つの選択肢がありました。

リンク作成後->更新してクリック。

まずはhtmlのリンクを作成します。

<a download id="downloadLink" #downloadLink style="display:none;"></a>

‘download’が書いてあるので、ブラウザーがリンクされてるファイルを開こうとせずに、ダウンロードする。

Angularの〇〇.component.tsの中からhtmlをアクセスする方法はこんな感じです:

@ViewChild('downloadLink') downloadLink: ElementRef;

では、このhtmlをどう編集すればいいでしょうか?

this.downloadService.getDownloadUrl(myVariables).subscribe(
       myUrl => { //サーバーからurlをもらって、
                 // 上記のリンクを更新して
        this.downloadLink.nativeElement.href = myUrl; 
        this.downloadLink.nativeElement.click(); 
                  //終わったら、クリックできなくする。
        this.downloadLink.nativeElement.removeAttribute('href');
        }
);

をやって見たら何も文句言わずにダウンロードできました。

結論

こういうものでしょうかな。ワーニング付けの一つめの方法と最後の方法のどっちのほうが好み次第だと思います。 個人的にワーニングをなくそうと頑張ってるつもりながら、2番目の方法は本来ユーザーがするはずのリンククリックをプログラムで実行してるのでちょっとづるいと思ってるところもありました。