viewIf
ElmでDOMを扱う時にviewIf
という関数をよく使う
viewIf : Bool -> Html msg -> Html msg
viewIf condition content =
if condition then
content
else
text ""
こいつを使うとログアウトボタンを表示するかどうかなどスッキリかける
a [ onClick CleanupAuthMsg, class "logout" ]
[ span [ class "text-logout" ] [ text logout ] ]
|> viewIf isShowLogout
setAttributeIfが欲しい
同じようにsetAttributeIfみたいな関数を作りたくてチャレンジしたのが今回の記事
探したところarowMさんの記事に行き当たった、そこには
Attributes.none
なんて値があったためこれを使えば
setAttributeIf : Bool -> Attribute msg -> Attribute msg
setAttributeIf condition attribute =
if condition then
attribute
else
Attributes.none
が定義できて例えばPC/Mobileでイベントを出し分けたい時に
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のページだけでなく、このパッケージにもあるように
attributeIf : Bool -> Attribute msg -> Attribute msg
attributeIf bool attribute =
if bool then
attribute
else
class ""
こいつを採用することも考えたのだけれど
class ""
これが例えばすでにclassが設定されている要素に対して追加された場合どうなるのだろうという懸念がぬぐい去れなかったためredditでもっとも汎用性高く記述できる以下の例を採用することに落ち着いた
justIfとList.filterMapによる解決
まずExMaybeモジュールなどを作りjustIf関数を定義する
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して切り落としてあげると他所でも使えそうな汎用性を持った記述ができる
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
以上。