I'm trying to implement dynamic column resizing on a table (like in Excel or Google Sheets).
In my render function I use the handle
callback when the user clicks mouse down on my resize control:
<div
className="resizer"
onMouseDown={self.handle(handleColumnResizeStart)}
/>
In the handler I want to add a new event listener for mousemove so that when the user is "dragging" we can draw something to indicate where the new column edge would end up.
Within the mousemove handler I was thinking I could send a reducer action that contained the mouse clientX coordinate to update the component state so that the render function could draw something while they are dragging.
let handleColumnResizeStart = (evt, self) => {
/* this handler gets invoked when the mouse is moved */
let handleMouseMove = evt => {
Js.log(evt); /* in js land I can see that clientX is in that evt object */
Js.log(ReactEvent.Mouse.clientX(evt)); /* but this creates type errors */
};
/* adds an event handler using the bs-webapi module */
Webapi.Dom.EventTarget.addEventListener(
"mousemove",
handleMouseMove,
document,
);
};
When I try to use ReactEvent.Mouse.clientX(evt)
to get the specific int value of clientX, I get this error:
25 Webapi.Dom.EventTarget.removeEventListener(
26 ┆ "mousemove",
27 ┆ handleMouseMove,
28 ┆ document,
29 ┆ );
This has type:
ReactEvent.Mouse.t => unit
But somewhere wanted:
Dom.event => unit
The incompatible parts:
ReactEvent.Mouse.t (defined as
ReactEvent.synthetic(ReactEvent.Mouse.tag))
vs
Dom.event (defined as Dom.event_like(Dom._baseClass))
>>>> Finish compiling(exit: 1)
My understanding of the type system is limited here and I'm not sure how to get the value of the mouse clientX coordinate into variable.
Although events received from React and from event handlers attached directly to the DOM may look similar, they are in fact different. React doesn't give you a raw DOM event, but a SyntheticEvent, and in Reason they've therefore been given different types, which is what the type error is informing you of. You can't use a
Dom.event
where aReactEvent.Mouse.t
is expected. In this caseevt
is aDom.event
, because it was acquired by attaching an event handler directly to the DOM usingbs-webapi
, andReactEvent.Mouse.clientX
of course expects aReactEvent.Mouse.t
.So instead of using
ReactEvent.Mouse.clientX
, you should useWebapi.Dom.MouseEvent.clientX
.Unfortunately that still won't work, because
Webapi.Dom.MouseEvent.clientX
expects aDom.mouseEvent
, not aDom.event
, which is the supertype of all DOM event types and too general to be used with functions specific to mouse events. And this in turn is becauseWebapi.Dom.EventTarget.addEventLsitener
isn't able to understand that"mousemove"
means it is a mouse event. You should instead useWebapi.Dom.EventTarget.addMouseMoveEventListener
, which does give you aDom.mouseEvent
.Note that the type error you get is more confusing than it needs to be, because it will infer the type and point to the error being somewhere other than where you perceive the error to originate. It's a good idea to annotate the types, at least when you get a type error you struggle to understand. That way the compiler won't infer the type to be something you don't expect it to be, and will contain the origin of the error.
You might also want to use
Webapi.Dom.Document
instead ofWebapi.Dom.EventTarget
.Document
inherits everything inEventTarget
, but will both document and constrain the type you operate on.