LoginSignup
41
19

More than 3 years have passed since last update.

Elmで性格診断的なサイトを作ってみた

Last updated at Posted at 2019-07-30

こんなサイト作ってみました

ソースコード
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タグのvalueonInputと、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タグのvalueStringしか値を取りえないため、もう一方の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描画とかやりたいなぁ。


  1. そのとき、いろいろと工夫したのがこちらのcommitになります。気合で文字列を生成して、その順番でどちらが押されているかをとるという力技です。 

  2. あとで分かったのですが、onInputvalueのStringの値をとってmsgになればよいので、onInputに渡すMsgに減らす属性を渡すという方法もありでした。 

  3. elm-modalやelm-dialogなんてのもありましたが、どれも古く、サポートされてないようでした。 

41
19
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
41
19