読者です 読者をやめる 読者になる 読者になる

ITの隊長のブログ

ITの隊長のブログです。いや、まだ隊長と呼べるほどには至っていないけど、日々がんばります。CakePHPとPlayFrameworkを使って仕事しています。最近はAngular2をさわりはじめたお(^ω^ = ^ω^)

PlayFrameworkのinputRadioGroupが使いづらいから自分で作った(ググってコピペしたが正しいです)

Scala Play Framework

スポンサードリンク

http://www.flickr.com/photos/10856846@N07/4426231119
photo by formalfallacy @ Dublin (Victor)



今度Scalaの書籍買ってこ。


ネットサーフィンしているとこれがいいらしい。


Scalaスケーラブルプログラミング第2版

Scalaスケーラブルプログラミング第2版



Scalaをわからないまま手を動かしたせいで2日かかりました。メモします。



やりたかったこと


デザイナーからもらったhtmlソースでradioボタンがこんな感じでした。

<div class="group">
    <label class="gLeft">デザイン <span class="notes nOrange">必須</span>
    </label>
    <div class="gRight">
        <div class="cf">
            <div class="floatBox">
                <label>
                    <input type="radio" name="design" id="design_0" value="0"> 使わない
                </label>
            </div>
            <div class="floatBox">
                <label>
                    <input type="radio" name="design" id="design_1" value="1"> 使う
                </label>
            </div>
        </div>
    </div>
</div>


しかし、PlayFrameworkのinputRadioGroupはこんな感じのhtmlが出力される。

@helper.inputRadioGroup(field = formValue("design"), options("0"->"使わない","1"->"使う"), 'name -> "design", '_label -> "design")
<dl class="" id="design_field">
    <dt>design</dt>
    <dd>
        <span class="buttonset" id="design">
            <input type="radio" id="design_0" name="design" value="0" checked="checked"/>
            <label for="design_0">使わない</label>
            <input type="radio" id="design_1" name="design" value="1" />
            <label for="design_1">使う</label>
        </span>
    </dd>
</dl>


これは良くない。と、いうか、ツカエナイ(°ω°


ということで、色々試してみた。

implicitで頑張る


これは教科書にも載っていたので、すぐ確認できた。もちろん時間はかかった。またimplicitは全く理解できていない。


しかし、これができたところで何も変わらなかった。正確には@helper.inputTextは問題なくできたが、@helper.inputRadioGroupがおかしいのだ。


このソースで@helper.inputRadioGroupを使いたい。ので、別途scalaテンプレートファイルを作成しそのファイルをimplicitして利用する形にした。

@import helper._

@inputRadioGroup(field = formValue("design"), options("0"->"使わない","1"->"使う"), 'name -> "design", '_label -> "design")(customInputRadioGroup, implicitly[Lang])
  • helper/customInputRadioGroup.scala.html
@(elements: helper.FieldElements)
<div class="group">
    <label class="gLeft">@elements.name <span class="notes nOrange">必須</span>
    </label>
    <div class="gRight">
        <div class="cf">
            @elements.input
        </div>
    </div>
</div>


するとですよ。。。。

<div class="group">
    <label class="gLeft">design <span class="notes nOrange">必須</span>
    </label>
    <span>
      <span class="buttonset" id="design">

          <input type="radio" id="design_0" name="design" value="0" checked="checked">
          <label for="design_0">使わない</label>

          <input type="radio" id="design_1" name="design" value="1">
          <label for="design_1">使う</label>

      </span>
    </span>
</div>


じゃーん!!!!orz



このspan -> input, labelと出力される!!!この形!!!なんなの!!?


とても邪魔です。


んで、@elements.inputの中身も正規表現とか使って置換すればいいのかなと考えましたが、絶対スマートじゃないと思って、やめました。

helperを「使わない」という選択


日本のサイトからアメリカに渡米したのにもかかわらず、stackflowをさまよい続けた結果全然わからなかった。


ということで、1日あぼーんしたので、radioボタンだけhelperを使うことをやめました。



しかし、すぐに問題が起こった!!!



値が引き継がれなくなりました。(あたりまえっちゃー、当たり前ですが)


そうです。これまでForm.classで、できることができなくなりました。自分で書かないといけなくなりました。


この時点ですごくだるくなっていました。俺がとるべき行動は次の2つありました。

  • 自分で書く
  • helperをカスタマイズする


ちなみにJavaScalaも初心者レベルなので、ぜってー自分で書きたくありませんでした。勉強にはいいかもしれませんが、時間が足りない。


あきらめて、helperをどうにかしてカスタマイズすることに決定。

結局使うことに


ひとつ気がついたことがあるんです。


そもそもですよ。helperも関数(メソッド?呼び方は知らん)である。関数なんですよ。


じゃあ、オーバーライドとかもできるんじゃね? また別途似たような関数を用意しちゃえばいいんじゃね? と思いつきました!


さぁどうする?


もちろんググる


欲しいデータはよはよ

  バン   はよ
バン (∩`・ω・) バン はよ
  / ミつ/ ̄ ̄ ̄/
  ̄ ̄\/___/

そして見つけました。それっぽいコードを!!!


groups.google.com


@**
 * Generate an HTML radio group for Bootsrap
 *
 * Example:
 * {{{
 * @inputRadioGroup(
 * contactForm("gender"),
 * options = Seq("M"->"Male","F"->"Female"),
 * '_label -> "Gender",
 * '_error -> contactForm("gender").error.map(_.withMessage("select gender")))
 *
 * }}}
 *
 * @param field The form field.
 * @param args Set of extra HTML attributes.
 * @param handler The field constructor.
 *@
@(field: play.api.data.Field, options: Seq[(String,String)], args: (Symbol,Any)*)(implicit handler: FieldConstructor, lang: play.api.i18n.Lang)

@input(field, args:_*) { (id, name, value, htmlArgs) =>
    @options.map { v =>
        <div class="floatBox">
            <label for="@(id)_@v._1" class="radio"></label>
                <input type="radio" id="@(id)_@v._1" name="@name" value="@v._1" @(if(value == Some(v._1)) "checked" else "") @toHtmlArgs(htmlArgs)> @v._2
            </label>
        </div>
    }
}

Foooooooooooo!!!!


どうやって使えばいいのか全然わからないぜぇっ!!! orz


とりあえず、適当に使ってみる。


このファイルをこんな感じに修正しました。

  • helper/bootstrapInputRadioGroup.scala.html
@(field: play.api.data.Field, options: Seq[(String,String)], args: (Symbol,Any)*)(implicit handler: FieldConstructor, lang: play.api.i18n.Lang)

@input(field, args:_*) { (id, name, value, htmlArgs) =>
    @options.map { v =>
        <div class="floatBox">
            <label>
                <input type="radio" id="@(id)_@v._1" name="@name" value="@v._1" @(if(value == Some(v._1)) "checked" else "") @toHtmlArgs(htmlArgs)> @v._2
            </label>
        </div>
    }
}

そして呼び出す箇所でこんな感じで書いてみる。

@import helper._
@bootstrapInputRadioGroup(field = formValue("design"), options("0"->"使わない","1"->"使う"), 'name -> "design", '_label -> "design")(contactFormRadio, implicitly[Lang])
  • helper/customInputRadioGroup.scala.html
@(elements: helper.FieldElements)

<div class="group">
    <label class="gLeft">@elements.label <span class="notes nOrange">必須</span></label>
    <div class="gRight">
        <div class="cf">
            @elements.input
        </div>
    </div>
</div>


するとですよ!!!!


エラーです(´;ω;`)ブワッ

[ambiguous implicit values:
both method implicitJavaLang in object PlayMagicForJava of type => play.api.i18n.Lang
and value lang of type play.api.i18n.Lang
match expected type play.api.i18n.Lang]


とりあえず全然よくわからない。調べてみてもよくわからないが、なんかScalaのバージョンが上がって、implicitするときには「play.api.i18n.Lang」はいらないよって記述っぽいのがあった!!(よくわからないので鵜呑み禁止。知っている人いましたら教えてほしい><)


というわけで削除

  • helper/bootstrapInputRadioGroup.scala.html
@(field: play.api.data.Field, options: Seq[(String,String)], args: (Symbol,Any)*)(implicit handler: FieldConstructor)

@input(field, args:_*) { (id, name, value, htmlArgs) =>
    @options.map { v =>
        <div class="floatBox">
            <label>
                <input type="radio" id="@(id)_@v._1" name="@name" value="@v._1" @(if(value == Some(v._1)) "checked" else "") @toHtmlArgs(htmlArgs)> @v._2
            </label>
        </div>
    }
}

んで、エラーです(´;ω;`)ブワッ

too many arguments for method apply

でも、こんぐらいなら俺でもわかるお!(^ω^ = ^ω^)


あれでしょ。引数が多いんだよね。


implicitの箇所でimplicitly[Lang]を削除して、引数を合わせました。

@import helper._
@bootstrapInputRadioGroup(field = formValue("design"), options("0"->"使わない","1"->"使う"), 'name -> "design", '_label -> "design")(contactFormRadio)


すると・・・・!!!

<div class="group">
    <label class="gLeft">design <span class="notes nOrange">必須</span></label>
    <div class="gRight">
        <div class="cf">
            
    
        <div class="floatBox">
            <label>
                <input type="radio" id="design_0" name="design" value="0" checked=""> 使わない
            </label>
        </div>
    
        <div class="floatBox">
            <label>
                <input type="radio" id="design_1" name="design" value="1"> 使う
            </label>
        </div>
    

        </div>
    </div>
</div>

でーきましたぁあああああああああああああああああああああああああ!!!!!!



よっしゃあああああああああああああああああああああああ!!!!!!




(゚∀。)ワヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャヒャ


まとめ


カスタマイズできた。


よかった。


でも、Scala構文しらないままよくない


先輩にURL教えてもらった。


スケーラブルで関数型でオブジェクト指向なScala入門


sites.google.com



そしてある程度理解したら、さらなる上を目指すため、ジュンク堂に行ってまいります。


隊長からは以上です。

追記 2015/07/26


元のテンプレートはgithubのここから探すのがいいかも

github.com