How to check if an HTMLElement has a dataset key

Hello everyone,

I am trying to move my JS code to ReScript to reduce the risk my end users get into fatal JS errors.

I have a function which takes an HTMLElement, and check if some dataset are present before working with this element. I cannot find in the documentation how the “Dom.htmlElement” is shaped, nor I cannot find the source code for this type declaration.

This is what I tried so far:

let loadingButton = (element: Dom.htmlElement): option<bool> => {
  if element.dataset {
    None
  } else {
    None
  }
}

I get this error

  1 │ let loadingButton = (element: Dom.htmlElement): option<bool> => {
  2 │     if element.dataset {
  3 │         None
  4 │     } else {

  The record field dataset can't be found.
  
  If it's defined in another module or file, bring it into scope by:
  - Prefixing it with said module name: TheModule.dataset
  - Or specifying its type:
  let theValue: TheModule.theType = {dataset: VALUE}

Does anyone has a clue how to get the dataset key/value list?

You can use https://github.com/tinymce/rescript-webapi

Webapi.Dom.HtmlElement.dataset

1 Like

I tried to use this library, but the dataset type is not found as well (but I can see it in the source code). The documentation is not of much help, so I deep dived into ReScript JS interop and ended up with this working solution:

type classList = {
  foo: string
}

type htmlElement = {
  localName: string,
  dataset: Js.Dict.t<string>,
  classList: classList
}

type document

@val
external htmlElement: htmlElement = "HtmlElement";

@val
external document: document = "document";

@send
external querySelector: (document, string) => Js.Nullable.t<htmlElement> = "querySelector";

@send
external addEventListener: (htmlElement, string, () => unit) => unit = "addEventListener";

@send
external add: (classList, string) => unit = "add";

@send
external remove: (classList, string) => unit = "remove";

let loadingButton = (element: htmlElement): unit => {
  addEventListener(element, "submit", () => {
    let loadingButtonSelector = switch Js.Dict.get(element.dataset, "loadingButton") {
      | Some(value) => value
      | None => ""
    }

    let buttonSelector = switch Js.Dict.get(element.dataset, "button") {
      | Some(value) => value
      | None => ""
    }

    if loadingButtonSelector !== "" && buttonSelector !== "" {
      let emptyHtmlElement = {
        localName: "",
        dataset: Js.Dict.fromArray([]),
        classList: {
          foo: ""
        },
      }

      let loadingButton = switch Js.Nullable.toOption(querySelector(document, loadingButtonSelector)) {
        | Some(element) => element
        | None => emptyHtmlElement
      }

      let button = switch Js.Nullable.toOption(querySelector(document, buttonSelector)) {
        | Some(element) => element
        | None => emptyHtmlElement
      }

      if (loadingButton.localName !== "" && button.localName !== "") {
        remove(loadingButton.classList, "d-none");
        add(button.classList, "d-none");
      }
    }
  })
}

If you show not working code with rescript-webapi, I can find why it didn’t work.