こんなサイト作ってみました
ソースコード
https://github.com/niso1985/FiveLoveLanguages
両方とも、自分が通ってる教会で教えてもらった内容ですが、紙でしかもらわなかったので、Webでできるといいなと思い、Elmも勉強中だったため作ってみました。
フロントはHTML/CSS/JavaScriptがどうも性に合わなくて手を出していなかったので、Web初心者がElmでフロントアプリ作ってみて得られた所感をお伝えできたらなと思います。
あんまりElm関係ない内容のほうが多いと思います。
ハマったところ
radioボタンにハマる
表示にハマる
Elmでのradioボタンの実装の資料がすぐに見つからなかったので、そもそもradioボタンをどう表示ささせるんだ?というところにハマりました。
input [ type_ "radio" ][]
これでOK。
※追記
@ossan_pg さんがわかりやすい記事書かれていました!
https://qiita.com/ossan_pg/items/43063b8be6b0c63c4ce8
ModelとViewは1:1対応にした方が良さげ
具体的にはinputタグのvalue
とonInput
と、Modelの関係性でハマりました。
もともと、Modelは下記のように、どの属性のボタンが何個選択されているか、という形で管理しようとしていました。
type alias Model =
{ ministries : Dict String Int }
init : Model
init =
{ ministries = |
Dict.fromList |
[ ( "Apostles", 0 )
, ( "Prophets", 0 )
, ( "Evangelists", 0 )
, ( "Shepherds", 0 )
, ( "Teachers", 0 )
]
}
各属性("Apostles"など)を持つradioボタンを押すと、その属性に対応した連想配列の値が加算されていくという考え方です。
ところが、Modelをこのような形にしてしまうと、同じグループのradioボタンを押した時に、別のradioボタンの属性の値を減らす必要が出てきてしまいます。
例えば、
- radioA
- radioB
の時、
A: 1
B: 0
だったのが、radioBを選択すると、Bに+1は良いとして、Aを-1しないといけません。
しかし、inputタグのvalue
はString
しか値を取りえないため、もう一方のradioボタンの属性値を渡す際にいろいろと工夫が必要になってきます。 1 2
これを簡単にするためには、下記のように1radioボタンの状態を1要素で管理するとすると、コードがとても簡単になりました。
type alias Model =
{ answers : Array MinisterType }
init : Model
init =
{ answers = Array.repeat 30 None }
このあたりは@ababup1192さんに色々とアドバイスを頂きました。ありがとうございます。
CSS使うときにBrowser.sandboxからBrowser.elementに変更するところにハマる
elm-guideのこのページの内容。
単純に見逃してハマってました。
<div id="elm"></div>
がサラッと書かれすぎててスルーしちゃってました。
こちらはGadaさんに助けていただきました。ありがとうございます。
モーダルの実装に悩む
モーダルの実装をはじめはHTML/CSSでなんとかやってみようと思ったのですが、巷のモーダルの実装の解説ページはJavaScriptが絡んでいる方法が多かったり、HTML/CSSもごちゃごちゃしてたりでイマイチうまくいきませんでした。3
調べてみると、Bulma-Model-Fxというものを見つけて、これであっという間に解決しました。
Bulmaがマジで有能です。
GAS使おうとしてCORSにハマる
診断結果を保存するために、GASにPOSTしようとしたのですが、CORS制約で引っかかってしまいました。
はじめはJSONPの実装を行おうかなと思ったのですが、@arowMさんにアドバイス頂き、NetlifyだとCORS制約を回避できるということを聞き、見事うまくいきました。
ありがとうございます。
方法はすごく簡単。
まずelm-httpで普通にpost requestを書きます。
postResult : Model -> Cmd Msg
postResult model =
Http.request
{ method = "POST"
, headers = [ Http.header "Accept" "application/json", Http.header "Content-Type" "application/json" ]
, url = "/api/"
, body = Http.jsonBody (makeJsonBody model)
, expect = Http.expectString Response
, timeout = Nothing
, tracker = Nothing
}
このとき、urlをNetlifyローカルのendpointを指すようにします。(今回は/api/としました。)
次に、_redirectsという下記のように、request時のendpointとPOSTしたいGASのURLを書いたファイルをprojectのルートディレクトリに配置します。
/api/ https://script.google.com/macros/s/XXXXXXXXXXXXXXXX/exec 200
これだけで、GASへのCORS制約を回避することができます。
所感まとめ
Elm(・∀・)イイ!!
やっぱりHTMLをプログラマブルに書けるのは良いですね。多少のボイラープレートはありますが、HTMLベタ書きよりも断然書きやすいです。
Scalaを普段使用しているのですが、パイプを利用すれば、ScalaのコレクションとElmのコレクションの使用感が殆ど変わらないのも良いです。
また、よく言われますが、Elmは実行時エラーがほとんどないのもとても良いです。
JavaScriptはundefinedに悩まされたトラウマがあるので、コンパイルが通りさえすれば動作が保証されるという安心感はとても良いです。
CSS書かなくてもなんとかなるやん
HTML/CSS/JSの御三家のなかで、一番苦手なのがCSSなのですが、Bulmaで作ってみたところ、ほとんどCSSらしいCSS書かなくても、それっぽくなったのに感動しました。
CSSとかワケワカラン、デザインとか無理ゲーすぎる、と考えているバックエンドや組み込み畑の人でも、それなりのデザインや動きを作れるCSSフレームワークはすげーです。
deployがほんとに簡単
Github pagesもNetlifyもそうですが、本当に簡単にWebページが公開できるなと感じました。
自分のWebページを公開するために、パソコン潰してサーバーにしてApacheたてて・・・ってやってた時代が懐かしい笑
CI的なことは規模も小さいのでスルーしてます。
サーバーレス便利
今回はバックエンドというほどではないですが、データ保存の要件もあったので、GASを使いました。
GASは軽くデータを保存したいときにはほんとに便利ですね。
謝辞
Elmではじめての作品を作るに当たり、elm-jpコミュニティの方にいろいろアドバイスを頂きました。
Elmコミュニティの方は回答も早く、とても初学者に優しい、学べる環境だなと思います。
コミュニティ自体にElmの言語的特性が浸透している気がします。
Elmのおかげでフロントが楽しくなってきたので、次は何を作ろうかなぁと考えています。
最終的にはWebGL使ったゴリゴリな3D描画とかやりたいなぁ。
-
そのとき、いろいろと工夫したのがこちらのcommitになります。気合で文字列を生成して、その順番でどちらが押されているかをとるという力技です。 ↩
-
あとで分かったのですが、
onInput
はvalue
のStringの値をとってmsg
になればよいので、onInput
に渡すMsg
に減らす属性を渡すという方法もありでした。 ↩ -
elm-modalやelm-dialogなんてのもありましたが、どれも古く、サポートされてないようでした。 ↩