Webアプリケーションを作っていて、何らかのアクションの後にポップアップを開きたい場面があると思います。例えば『とあるデータを登録して、登録が完了した後にポップアップでプリント画面を開きたい』場合とか。
普通に考えると、登録後に遷移する画面内のJavascriptでwindow.open
すれば良さそうですが、これはブラウザのポップアップブロック機能に引っ掛かります。ポップアップを許可してあげれば問題ないのですが、不特定多数に使ってもらうWebサービス等の場合は、なるべくならセキュリティ警告をユーザーに見せたくはありません。
そんなときの常套手段のひとつとして、
- 登録ボタンクリック時に、あらかじめポップアップを開いておき
- 登録完了後にさっき開いたポップアップをリロードする
という手が用いられます。1はポップアップブロックに引っ掛かりません。click
のように、『ユーザーが意図的に起こすアクション』内にはポップアップを開く処理を書いても大丈夫なのです。
これを実現する具体的なコードのイメージは次のような感じになります。
📄登録画面.js
$('.submit').on('click', function(e) { window.open('', 'popup'); });
📄登録完了後の画面.js
var popup = window.open('', 'popup'); popup.location.href = '/print';
登録時にバリデーションエラーがあった場合は、開いてしまったポップアップを閉じてやります。
📄登録画面.js
var popup = window.open('', 'popup'); popup.close();
流れとしては↓こんな感じ↓になります。
先にポップアップが開いてしまうのは少々格好悪いですが、一応目的は達成できました。WithPopupはこれと同じことをやってくれるrails用のgemです。
WithPopup
まずはインストールの仕方から。Gemfileに次のコードを追加します。
📄Gemfile
gem 'with_popup'
bundler使ってない人はgem install with_popup
してください。
次にapp/assets/javascripts/application.js
を編集して、with_popupをjqueryより後に記述します。
📄application.js
//= require jquery //= require jquery_ujs //= require with_popup //= require_tree .
使い方
クリックを伴うようなDOMを生成するForm用のヘルパー(link_to
とかsubmit_tag
とか)をラップしています。前段の登録後にプリント画面を開く例をコードにすると、次のような感じになります。
📄登録画面.html.erb
<%= form_for @post do |f| %> ... # Submit while opening a popup window <%= f.submit_with_popup %> <% end %>
f.submit_with_popup
という箇所が通常とは違うところ。これはf.submit
と書くのと同じ(透過的に委譲している)で、submiと同時にポップアップを開いてくれます。
開いたポップアップの命運はコントローラが決めます。
📄登録アクション.rb
def create @post = Post.new(params[:post].permit(...)) if @post.save # Show print preview in the popup window you've opened reload_popup print_post_path(@post) redirect_to @post else # Close the popup window close_popup render :new end end
基本的な使い方はこれだけです。Javascriptは一切書く必要はありません。簡単でしょ?
その他詳細はgithub上に記載しています。かなりニッチなニーズしかないと思いますが、何かの役に立てばと幸いです。
リンク
関連する記事
- ポップアップブロックを回避してsubmitと同時に新しいウィンドウを開く
- Railsアプリを『浅く』パフォーマンス・チューニングしてみる(その3)
- chosen-railsによる検索機能付きセレクトボックスで、検索画面作成の手間を省く
- Rails+JSフレームワークでリアルタイム掲示板を作成してみる(Backbone.js編)
- Rails+JSフレームワークでリアルタイム掲示板を作成してみる(AngularJS編)