LoginSignup
9
1

More than 3 years have passed since last update.

Elm 条件次第でHtml要素に属性を追加

Last updated at Posted at 2019-08-06

viewIf

ElmでDOMを扱う時にviewIfという関数をよく使う

Util.elm
viewIf : Bool -> Html msg -> Html msg
viewIf condition content =
    if condition then
        content

    else
        text ""

こいつを使うとログアウトボタンを表示するかどうかなどスッキリかける

View.elm
a [ onClick CleanupAuthMsg, class "logout" ]
  [ span [ class "text-logout" ] [ text logout ] ]
      |> viewIf isShowLogout

setAttributeIfが欲しい

同じようにsetAttributeIfみたいな関数を作りたくてチャレンジしたのが今回の記事

探したところarowMさんの記事に行き当たった、そこには

Attributes.none

なんて値があったためこれを使えば

Utils.elm
setAttributeIf : Bool -> Attribute msg -> Attribute msg
setAttributeIf condition attribute =
    if condition then
        attribute
    else
        Attributes.none

が定義できて例えばPC/Mobileでイベントを出し分けたい時に

View.elm
div
    [ class "hoge"
    , onMouseLeave HogeMsg
        |> setAttributeIf (device == Pc)
    ]
    [ xxxx ]

みたいにかけていいなあと思ったのだけれど

これらを使うには arowM/html に 乗り換える 必要があります。
arowM/html は elm/html を 置き換える という戦略をとっています。

これがチームの方針的に採用できなかったので代替案を探したところredditでの議論を見つけた

Adding an attribute based on some condition? | Reddit

結構みんな同じことやりたいんだなあ、としみじみ。

また上記redditのページだけでなく、このパッケージにもあるように

Utils.elm
attributeIf : Bool -> Attribute msg -> Attribute msg
attributeIf bool attribute =
    if bool then
        attribute

    else
        class ""

こいつを採用することも考えたのだけれど

class ""

これが例えばすでにclassが設定されている要素に対して追加された場合どうなるのだろうという懸念がぬぐい去れなかったためredditでもっとも汎用性高く記述できる以下の例を採用することに落ち着いた

justIfとList.filterMapによる解決

まずExMaybeモジュールなどを作りjustIf関数を定義する

ExMaybe.elm
justIf : Bool -> a -> Maybe a
justIf condition x =
    if condition then
        Just x

    else
        Nothing

そいつを用いて条件がTrueならJust (Attrinbute msg)を返し、FalseならNothingを返してやる

そしてList.filterMapでList内の要素のうちNothingだけをfilterして切り落としてあげると他所でも使えそうな汎用性を持った記述ができる

View.elm
div
    ([ Just (class "hoge")
     , onMouseLeave HogeMsg |> ExMaybe.justIf (device == Pc)
     ]
        |> List.filterMap identity
    )
    [ xxxx ]

最後に、filterMapとidentityの定義と使用例を載せておく

filterMap : (a -> Maybe b) -> List a -> List b

numbers : List Int
numbers =
  filterMap String.toInt ["3", "hi", "12", "4th", "May"]

-- numbers == [3, 12]

filterMapってfilterとMap両方の特性を持っていて面白い

identity : a -> a

P.S
viewIfに関してもFalseの場合text ""を返すことでInternet ExplorerでMsgが飛ばないバグが見つかっている、elmの文脈では慣習的にviewIfの中でtext ""がよく使われるけれど、今回のようにfilterMapするなどの対応の方がBetterかもしれない

Bug on IE (11,10) - nested Html.map(ed) submodule #156

以上。

9
1
2

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
9
1