Comments (5)
A fifth solution could be to add external "overloads" for each event type:
external addMouseMoveListener : _ [@bs.as "mousemove"] => (mouseEvent => unit) => unit = "addEventListener" [@@bs.send.pipe: t];
This should provide good performance, no code generated, good documentation and can be implemented incrementally. The only downside seems to be that it deviates from the DOM API, but that's not much of an issue.
from bs-webapi-incubator.
Indeed they are.
One possible solution, which I hinted at on Discord, is to have casting functions in each specialized event module, e.g. MouseEvent.fromEvent
. This would return an option and be rather cumbersome to use though, but is simple and easy to implement.
Another solution is to use polymorphic variants as described in the BS manual, but for addEventListener
(and removeEventListener
) that would become an absolutely massive external declaration, and would need to be duplicated for each of the six overloads. How would that look in the docs?
A third solution is to wrap it in a function that uses an ordinary variant, e.g. addEventListener (MouseMove (fun e -> doSomethingWith (MouseEvent.clientX e))
, but since EventTarget
is implemented by just about everything it would cause significant code bloat.
A fourth possible solution, for some use cases at least, would be to implement each and every on...
property for each applicable type, which is no small task but can be done incrementally. This covers a slightly different use case than addEventListener
however, and is generally discouraged since it's very error-prone.
And finally, this is just one of many issues caused by the very dynamic nature of the DOM API, and the solution to this should preferably be consistent with the solutions used elsewhere in the API. The reason it is in such a sorry state is that I just don't know what the right trade-offs are (yet). Of course I'd appreciate any input on this.
from bs-webapi-incubator.
Thoughts as a beginner:
MouseEvent.fromEvent
This suffers from low-discoverability and awkwardness. If I find this option and understand that I can use it to convert types, I now have an option type that I have to deal with. This all feels silly when I know good and well that I have a FooEvent. Clearly this type nonsense isn't worth the frustration.
polymorphic variants
iiuc this might look bad in the generated docs, but would actually function how a JS developer thinks. Code examples and hand-written docs can go a long way towards making this easy to get started.
ordinary variant
I don't understand this 🤷♂️
implement each and every on... property
If this means having a bunch of setOnMouseMove
-like handlers that seems reasonable. While trying to figure out this issue I came across setOnClick
and wished that I could have just used something like that.
this is just one of many issues caused by the very dynamic nature of the DOM API
It seems like there is a line to walk here between "mimics DOM API's and is familiar to JS devs" and "doesn't require hoops to jump through to type correctly". I don't have any intuition about what would feel idiomatic in Reason yet, so my question is: How would design an API to bind to events in a UI if you weren't trying to mimic the DOM's API?
from bs-webapi-incubator.
This suffers from low-discoverability and awkwardness.
Agreed.
Code examples and hand-written docs can go a long way towards making this easy to get started.
The API surface for the DOM is absolutely massive, and manually curated docs would be a huge additional burden. In the very very long term this might work, but in the short term it's not an option. Even just automatically generated html pages with lists of function signatures would be a big step up from what we have right now.
I don't understand this
An example would hopefully explain it better:
type eventType =
| MouseMove (mouseEvent => unit)
| ...
external addEventListener : string => ('a => unit) => unit = "" [@@bs.send.pipe: t];
let addEventListener (type_: eventType) (target: t) =
switch type_ {
| MouseMove callback => addEventListener "mousemove" callback target
| ...
}
It might also be possible using a GADT:
type 'a eventType =
| MouseMove : mouseEvent eventType
| ...
external addEventListener : string => ('a => unit) => unit = "" [@@bs.send.pipe: t];
let addEventListener (type_: 'a eventType) (callback: 'a => unit) (target: t) =
switch type_ {
| MouseMove => addEventListener "mousemove" callback target
| ...
}
If this means having a bunch of
setOnMouseMove
-like handlers that seems reasonable.
It would. As I said it's a very error-prone API, so I'm hesitant to expose it at all, but it's a very convenient way of doing ad hoc bindings in your own project.
How would design an API to bind to events in a UI if you weren't trying to mimic the DOM's API?
That would depend more on the nature and structure of the actual events I think. The DOM events are structured hierarchically, but even the event objects themselves are so dynamic it's hard to type them correctly. The target
property, for instance, will often refer to an object of a known type, but for events that bubble it might not.
An ergonomic and safe API is also not the only consideration, it should also be performant and lightweight. There's a desire to have these bindings be a relatively thin layer, upon which more ergonomic bindings can be built.
from bs-webapi-incubator.
Added the overloads described in my last comment. I have some further ideas to imrpveo the API too, but that involves changing the types that ship with bs-platform, and so needs some planning.
from bs-webapi-incubator.
Related Issues (20)
- Function for converting Node to real type HOT 1
- Project name HOT 2
- Nodelist forEach HOT 2
- Dom.Image does not exist (the current Dom.Image should be Dom.ImageData)?
- adding bindings to HtmlVideoElement HOT 3
- Binding for XHR HOT 1
- Classify for Dom.node HOT 4
- Adding replaceChild
- Canvas2d.putImageData creates erroneous calls when not using all the optionals. HOT 3
- Could be possible to perform auto-generation from WebIDL? HOT 3
- Bsdoc dependency makes contributing a bit difficult on Linux HOT 2
- Binding for URLSearchParams.entries() is incorrect
- Add bindings for HtmlTemplateElement
- unmet peer dependency warning HOT 1
- Regarding document.documentElement.scrollTop HOT 2
- Add functor to type CustomEvent.detail
- How to use HtmlInputElement (focus, select) ? HOT 5
- How to use addEventListener on window HOT 3
- Add DataTransfer bindings
- unsafeAsHtmlInputElement
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from bs-webapi-incubator.