Reputation: 265
Here's the short version:
I have a function:
onClick : String -> Bool -> (State -> msg) -> Options.Property c msg
onClick name isReversed toMsg =
Options.on "click" <| Json.succeed <|
toMsg (State name isReversed)
I want to change the function to this:
onClick : String -> Bool -> (State -> msg) -> (Maybe msg -> Options.Property c msg)
In other words, I'd like it to return a partial function which takes a Maybe msg. However, I'm not sure how to do that! Help would be appreciated.
Here's the long version:
I'm trying to build a 'fork' of the elm sortable table package which uses the elm mdl package and allows custom event listeners on the column headers. The sortable table package (obviously) applies event listeners on the column headers which sort the table by that column.
Unfortunately, you can't have two 'onClick' listeners on the same element, so what I've decided to do is to pass the custom message as an argument to the sort message, and then send it as a command from the sort update. Sorry if you're not familiar with the package and that all sounds like mumbo jumbo, I just thought I'd give the context for my question.
The developers of the sortable table package created a custom event listener which looks like this:
onClick : String -> Bool -> (State -> msg) -> Attribute msg
onClick name isReversed toMsg =
E.on "click" <| Json.map toMsg <|
Json.map2 State (Json.succeed name) (Json.succeed isReversed)
I've already changed it a bit to use the mdl custom event listener and to make it (in my opinion), slightly more readable:
onClick : String -> Bool -> (State -> msg) -> Options.Property c msg
onClick name isReversed toMsg =
Options.on "click" <| Json.succeed <|
toMsg (State name isReversed)
As I've said, I'd like it to be this:
onClick : String -> Bool -> (State -> msg) -> (Maybe msg -> Options.Property c msg)
However, if you're familiar with the package and have any other suggestions for using custom messages on clicking a column, please suggest them!! I really have no idea what I'm doing.
The longer version:
In the component's view code, there is a variable theadDetails
which looks like this:
theadDetails =
customizations.thead (List.map (toHeaderInfo state toMsg columns)
state
toMsg
and columns
all come from the config in the project's main view code. toMsg
is a Msg which is handled in the main update (the component doesn't keep track of its own state).
toHeaderInfo
looks like this:
toHeaderInfo : State -> (State -> msg) -> ColumnData data msg -> ( String, Status, Options.Property c msg )
toHeaderInfo (State sortName isReversed) toMsg { name, sorter } =
case sorter of
None ->
( name, Unsortable, onClick sortName isReversed toMsg )
Decreasing _ ->
( name, Sortable (name == sortName), onClick name False toMsg )
IncOrDec _ ->
if name == sortName then
( name, Reversible (Just isReversed), onClick name (not isReversed) toMsg )
else
( name, Reversible Nothing, onClick name False toMsg )
This is basically where the data that will be included in each element is rendered. All of this stuff about State
and sorter
has to do with how each column's sorting is configured and the current order. But you see, here onClick
is being called and passed the required arguments.
As you see in theadDetails, this info is then passed to an function, customizations.tHead
which looks like this:
defaultCustomizations : Customizations data msg c
defaultCustomizations =
{ tableAttrs = []
, caption = Nothing
, thead = simpleThead
, tfoot = Nothing
, tbodyAttrs = []
, rowAttrs = simpleRowAttrs
}
simpleThead : List ( String, Status, Options.Property { numeric : Bool, sorted : Maybe Table.Order } msg ) -> HtmlDetails {} msg
simpleThead headers =
HtmlDetails [] (List.map simpleTheadHelp headers)
simpleTheadHelp : ( String, Status, Options.Property { numeric : Bool, sorted : Maybe Table.Order } msg ) -> Html msg
simpleTheadHelp ( name, status, onClick ) =
let
check =
Debug.log "status" status
attrs =
case status of
Unsortable ->
[]
Sortable selected ->
if selected then
[ onClick
, Options.css "color" "rgb(0,0,0)"
]
else
[ onClick ]
Reversible Nothing ->
[ onClick
]
Reversible (Just isReversed) ->
[ onClick
, Options.css "color" "rgb(0,0,0)"
]
in
Table.th attrs [ Html.text name ]
It's precisely here where I'd like to pass the final argument. So simpleTheadHeald would become:
simpleTheadHelp : ( String, Status, Options.Property { numeric : Bool, sorted : Maybe Table.Order } msg ) -> Html msg
simpleTheadHelp ( name, status, onClick ) =
let
check =
Debug.log "status" status
attrs =
case status of
Unsortable ->
[]
Sortable selected ->
if selected then
[ onClick Nothing
, Options.css "color" "rgb(0,0,0)"
]
else
[ onClick Nothing ]
Reversible Nothing ->
[ onClick Nothing
]
Reversible (Just isReversed) ->
[ onClick Nothing
, Options.css "color" "rgb(0,0,0)"
]
in
Table.th attrs [ Html.text name ]
This, however, gives me an error saying onClick is not a function (because in the type definition it isn't expecting an argument).
Sorry for doing such a poor job explaining myself! I'm really trying to figure it out as I go, so I appreciate the patience.
Upvotes: 1
Views: 178
Reputation: 806
I'm not familiar with the package, so if I'm missing something in your question or telling you something you already know, I apologize.
Functions in Elm are curried automatically. All you need to do is pass the function an incomplete set of arguments, and you'll get back a function that takes the remaining argument(s). So this would be your function signature:
onClick : String -> Bool -> (State -> msg) -> Maybe msg -> Options.Property c msg
onClick name isReversed toMsg maybeMsg =
You then write the function, using all the arguments and not worrying about partial application at all. Calling that function with only the first three arguments, like this:
onClick "myName" True MyMsg
will automatically return a function with this signature:
newFunction : Maybe msg -> Options.Property c msg
You don't need to do anything else.
Upvotes: 1