reasonbucklescriptbs-webapi

Pass results of querySelectorAll to EventTarget.addEventListener


I want to do something like:

open Webapi.Dom;

let addListener = (element) =>
    EventTarget.addEventListener("click", onSubscribeClick, EventTarget.asEventTarget(element));

let addOrRemoveListeners = (handler, ()) => {
    let elements = Document.querySelectorAll({j|[$subscriptionIdAttr]|j}, document);
    Js.Array.forEach(handler, NodeListRe.toArray(elements) |> Js.Array.map(Element.ofNode))
  };

let addListeners = addOrRemoveListeners(addListener);

let removeListeners = addOrRemoveListeners(removeListener);

But I get an error in addOrRemoveListeners(addListener);:

This is:
  (Dom.eventTarget) => unit
But somewhere wanted:
  (Dom.node) => unit

How should I convert from Dom.eventTarget to Dom.node?


Edit: I ended up with this:

let addListener = Element.addEventListener("click", onSubscribeClick);
let removeListener = Element.removeEventListener("click", onSubscribeClick);
let addOrRemoveListeners = (handler, ()) => {
  let elements = Document.querySelectorAll({j|[$(subscriptionIdAttr)]|j}, document);
  let () =
    elements
    |> NodeListRe.toArray
    |> Array.map(Element.ofNode)
    |> Array.to_list
    |> List.filter(Js.Option.isSome)
    |> List.map(Js.Option.getExn)
    |> List.iter(handler);
  ()
};
let addListeners = addOrRemoveListeners(addListener);
let removeListeners = addOrRemoveListeners(removeListener);

Solution

  • Short answer:

    external eventTargetToNode : Dom.eventTarget => Dom.node = "%identity";
    

    An eventTarget can be almost anything, and there's unfortunately no good way of figuring out what it is. In JavaScript it's simply inferred by the user based on context (It might be possible to carry that context around in a type parameter, but that's off in the future somewhere).

    So for the moment you'll have to make an unsafe cast to get what you need.

    (BTW, you can use Element.addEventListener to avoid the cast from element to eventTarget)