7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ラジオボタンが非選択のときにブラウザが値を送信してくれない事象をsimple_formで何とかする方法

Posted at

困ったこと

ラジオボタンが非選択状態のとき、ブラウザはラジオボタン項目の値を送信してくれないのです(値がないから当然ですよねー)。

「非選択状態」という状態を保存したいとき、これだと保存されなくて困る。詰む。

解決方法

前提

rails4 + simple_form + twitter bootstrap3のマークアップです。

simple_form側の実装

こちらの記事で紹介されている方法をsimple_formで実装します。
radioボタンが非選択時、値を送信しないのに対応する

/app/inputs/collection_radio_buttons_input.rb
class CollectionRadioButtonsInput < SimpleForm::Inputs::CollectionRadioButtonsInput
  # @override
  def collection
    if translate(:options).present?
      translate(:options)
        .to_a
        .map { |elem| [elem.last, elem.first] }
        .push(['未回答', '']) # <= 空の項目を常に追加するようにする
    else
      super
    end
  end

  # @override
  def apply_nested_boolean_collection_options!(options)
    options[:item_wrapper_tag] = nil
  end

  # @override
  def build_nested_boolean_style_item_tag(collection_builder)
    hidden_class = collection_builder.value.blank? ? ' hidden' : ''
    collection_builder.label(class: item_wrapper_class + hidden_class) {
      collection_builder.radio_button + collection_builder.text
    }
  end

  # @override
  def item_wrapper_class
    'radio-inline'
  end
end

simple_formは基本的にオーバーライドして振る舞いを変えられるのが便利です。

collectionメソッドはラジオボタンの項目数が多すぎてもsimple_formでそこそこすっきり書く方法で紹介した、選択項目の値をconfig/locals/以下のファイルに書いてしまう方法を取り入れつつ、翻訳が存在する場合のみ空の項目を常に追加するようにしています(booleanのラジオボタンのときに誤判定する可能性もあるので、その辺考慮した方が良いです)。

こうやって空の項目を追加することで、「空白の値を持つラジオボタン」を作り出しているのです。

空白の値を持つラジオボタンは表示されないで欲しいので、build_nested_boolean_style_item_tagメソッドをオーバーライドして、空白の値の場合はhiddenクラスを追加するようにしています。hiddenにはdisplay: noneやらそんな感じのスタイルが定義されているので、表示上見えなくなるという寸法です。

ビュー側の実装

非選択状態のときは、内部的には空白の値を持つラジオボタンが選択されている状態でなければなりません。

そんな訳で、そういう風になるようにJavaScriptで制御してあげる必要があります。

今回は既に選択してあるラジオボタンをクリックすると、ラジオボタンが非選択状態になる、という振る舞いを実現します。

beforeRadioValue = null
$('input:radio').on 'mousedown', ->
  beforeRadioValue = $("input:radio[name='#{$(this).attr('name')}']:checked").val()
.on 'click', ->
  if $(this).val() == beforeRadioValue
    # 既に選択してあるラジオボタンをクリックしたときに、空白の値を持つラジオボタンが選択されるようにする
    $(this).closest('.form-group').find("input:radio[value='']").prop('checked', true)

これでサーバに空白の値が送信されるようになります。めでたしめでたし。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?