Using Html.Events.on to capture additional data from DOM events

186 views
Skip to first unread message

Justin Manley

unread,
Jul 31, 2015, 11:21:14 PM7/31/15
to Elm Discuss
I'd like to use Html.Events.on to create listeners which can capture additional data from DOM events. For example, Html.Events.mouseMove has the type Address a -> a -> Attribute. This type signature allows the developer to specify a value of type a to send to the specified address each time the event occurs, but that value must be predetermined, as in the todomv example; it can't be calculated from the payload of the event itself.

It seems plausible to use Html.Events.on to pass data from the payload to the event listener. I've tried to write a custom mousemove listener in this way, reporting on the position of the mouse in its parent container:

onMouseMoveCustom : Signal.Address (Maybe (Int, Int)) -> Html.Attribute
onMouseMoveCustom address
= Events.on "mousemove" offset (Signal.message address)

offset
: Json.Decoder (Maybe (Int, Int))
offset
= Json.map Just
   
<| Json.tuple2 (,) ("offsetX" := Json.int) ("offsetY" := Json.int)

Unfortunately, this custom listener doesn't work - it never fires. Digging into the internals of elm-html, I've determined that this custom listener is failing to fire because the JSON decoder is failing every time. Logging the value extracted in the native code invariably shows:

Object {ctor: "Err", _0: "Converting circular structure to JSON"}

Since the decoder is not successful, the listener never fires. It seems to me that this should be a very common problem, since most DOM event objects will contain circular references.

Is there a way to capture data from the payload of an event without running into this error?

Thanks in advance for any advice!

Justin





Dobes Vandermeer

unread,
Jul 31, 2015, 11:43:33 PM7/31/15
to Elm Discuss

Perhaps you could send the ID of the element instead of the element itself?


--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

James Byatt

unread,
Aug 1, 2015, 4:32:30 PM8/1/15
to elm-d...@googlegroups.com
On Sat, 1 Aug 2015 at 04:21 Justin Manley <manle...@gmail.com> wrote:

onMouseMoveCustom : Signal.Address (Maybe (Int, Int)) -> Html.Attribute
onMouseMoveCustom address
= Events.on "mousemove" offset (Signal.message address)

offset
: Json.Decoder (Maybe (Int, Int))
offset
= Json.map Just
   
<| Json.tuple2 (,) ("offsetX" := Json.int) ("offsetY" := Json.int)

I've recently been exploring this area; I've found elm-reactor and a breakpoint in the native "on" function very handy. Stop reading here if you don't want the solution spoiled!

Solution: tuple2 is not what you want...

tuple2 : (a -> b -> value) -> Decoder a -> Decoder b -> Decoder value
Handle an array with exactly two elements. Useful for points and simple pairs. 

The MouseMove event is an object, not an array, so I think 'object2' may well be what you need :-).

Cheers,
James. 

Corey Trampe

unread,
Aug 1, 2015, 5:01:06 PM8/1/15
to elm-d...@googlegroups.com
That's cool. I've been writing stuff like

    attribute "onMouseMove" "console.log(event);"

to inspect the event object.

--

Justin Manley

unread,
Aug 1, 2015, 5:28:08 PM8/1/15
to Elm Discuss
Thanks, James!

This is exactly what the problem was! I used tuple2 because I was trying to produce a tuple - didn't realize that I should have used object2.

Problem solved :)

Justin
Reply all
Reply to author
Forward
0 new messages