bs-webapi-incubator icon indicating copy to clipboard operation
bs-webapi-incubator copied to clipboard

How to use HtmlInputElement (focus, select) ?

Open Qziem opened this issue 4 years ago • 5 comments

I want to do simple thing. Just focus and select input field after click button. I have code like this:

[@react.component]
let make = () => {
  let inputRef = React.useRef(Js.Nullable.null);

  let handleSelect = _event => {
    let element =
      inputRef.current->Js.toOption->Belt.Option.flatMap(Webapi.Dom.HtmlInputElement.ofElement);

    switch (element) {
    | Some(input) =>
      Webapi.Dom.HtmlInputElement.focus(input);
      Webapi.Dom.HtmlInputElement.select(input);
    | None => ()
    };
  };

  <>
    <input
      className="new-leon-input"
      type_="text"
      value="abcd"
      onChange={_ => ()}
      ref={ReactDOMRe.Ref.domRef(inputRef)}
    />
    <button onClick=handleSelect> "select"->React.string </button>
  </>;
};

Compiler return a bug:

  We've found a bug for you!
  src/components/TestComponent.re 11:41-45
  
   9 ┆ switch (element) {
  10 ┆ | Some(input) =>
  11 ┆   Webapi.Dom.HtmlInputElement.focus(input);
  12 ┆   Webapi.Dom.HtmlInputElement.select(input);
  13 ┆ | None => ()
  
  This has type:
    Dom.htmlElement (defined as
      Dom.eventTarget_like(Dom._node(Dom._element(Dom._htmlElement(Dom._baseClass)))))
  But somewhere wanted:
    Webapi.Dom.HtmlInputElement.t_htmlElement (defined as
      Dom.eventTarget_like(Dom._node(Dom._element(Dom._htmlElement(Dom._htmlInputElement)))))
  
  The incompatible parts:
    Dom._baseClass
    vs
    Dom._htmlInputElement

What is wrong in this code ? This code was working with bs-webapi 0.15.9, with newest: 0.19.1 i have an error above. Maybe there is a bug in library ? I use bs-platform: 7.3.2

Qziem avatar Oct 06 '20 08:10 Qziem

It looks like the type of ofElement has changed to Webapi__Dom__Element.t => option(Dom.htmlElement) instead of option(Dom.htmlInputElement).

And it's another bug from #182 : https://github.com/reasonml-community/bs-webapi-incubator/pull/182/files?file-filters%5B%5D=.re#diff-f6590c311eac02db4a8591dfe7b1a4c232207269ed2d71105f8407ad4c5ba34dL13-R4

The type annotation on let ofElement: Dom.element => option(t_htmlElement) has been lost (I'm not even sure if it would be valid with the new implementation) so the function becomes effectively useless in scenarios where it's inherited by other modules.

cc @yawaramin

TheSpyder avatar Oct 20 '20 10:10 TheSpyder

Hello, any progress of this one? We've run into the same issue trying to access input's value in tests.

a-gierczak avatar Oct 30 '20 09:10 a-gierczak

Downgrade your version? It has been nearly a month and the maintainer hasn't responded 🤷‍♂️

TheSpyder avatar Nov 02 '20 04:11 TheSpyder

With 0.18, 0.17, 0.16 i have the same problem. With 0.15.9 works - but no with bs-platform 8.3.1. With bs-platform 8 and bs-webapi 0.15.9 i have an error:

We've found a bug for you!
  /home/leon/public_html/client/react/node_modules/bs-webapi/src/Webapi/Webapi__Dom/Webapi__Dom__DomStringMap.re:11:5-7
  
   9 │ let set = (key, value, map) => set(map, key, value);
  10 │ let unsafeDeleteKey: (key, t) => unit =  
  11 │   [%raw (key, map) => "delete map[key];"];
  12 │   
  
  bs.raw can only be applied to a string

I made workaround to have working with bs-platform 8 and newest bs-webapi, i just created my own functions using %raw (maybe it will be useful for someone):

let focus: Dom.element => unit = [%raw {| domElement => domElement.focus() |}];
let select: Dom.element => unit = [%raw {| domElement => domElement.select() |}];

[@react.component]
let make = () => {
  let inputRef = React.useRef(Js.Nullable.null);

  let handleSelect = _event => {
    let element = inputRef.current->Js.toOption;

    switch (element) {
    | Some(input) =>
      focus(input);
      select(input);
    | None => ()
    };
  };

  <>
    <input
      className="new-leon-input"
      type_="text"
      value="abcd"
      onChange={_ => ()}
      ref={ReactDOMRe.Ref.domRef(inputRef)}
    />
    <button onClick=handleSelect> "select"->React.string </button>
  </>;
};

But of course it would be much better to fix this library.

Qziem avatar Nov 02 '20 07:11 Qziem

Oh right, because the library had to be updated to work with some ReScript incompatibilities and this bug was introduced around the same time.

You could use external instead of raw, if you prefer, similar to how webapi does it

[@send] external focus: Dom.element => unit = "focus";
[@send] external select: Dom.element => unit = "select";

and then focus(input) will compile to input.focus().

TheSpyder avatar Nov 03 '20 11:11 TheSpyder