Implementing an onchange handler


#1

I have a web page with a <select> menu and want to add an onchange handler written in Reason (this is plain JS, not React). I tried writing a function like this:

let handleChange = (_evt) => { ... }

and in the HTML, used <select onchange="handleChange">, but this gives me a ReferenceError. Trying to set the attribute from Reason using Element.setAttribute gives the same result.

I am overlooking something obvious; what is it? [Edit: I am using parcel as a bundler.]


#2

Are you quoting handleChange?

Edit: Noticed they’re not using React zzz.


#3

In the HTML, yes; attribute values are implicitly quoted anyway as they are strings. Setting the onchange attribute from Reason via setAttribute also requires string arguments. (I tried removing the quote marks in the HTML and it didn’t solve the problem.)


#4

According to the W3C schools doc, you need to include the parens to invoke the function


#5

Tried that also, but the problem is that I get a ReferenceError changeConj is not defined, so even the parentheses won’t help to invoke a function that can’t be found in the first place.


#6

I used %bs.raw as a stopgap until I get a better solution:

let setOnChange: (Dom.element, ((Dom.event) => unit)) => unit = [%bs.raw {|
  function(element, fcn) {
    element.onchange = fcn
  }
|}];

/* then later in code */
setOnChange(inputElement, handleChange);

#7

I got this to work:

<!-- index.html -->
<!DOCTYPE html>
<html>
  <head>
    <script text="text/javascript" src="./Index.js"></script>
  </head>
  <body>
    <select onChange="f()">
      <option value="hi">Hi</option>
      <option value="bye">Bye</option>
    </select>
  </body>
</html>
/* Index.re */
let f = () => Js.log("hiya");

I get an error in the console because the browser doesn’t recognize the export, but that doesn’t affect it getting dumped in to the global scope. Maybe you’re importing your scripts after you’ve attempted to bind the function to the element?


#8

This should work:

let optionChangeHandler = (_: Dom.event) => {
  doSomething();
};


switch (optionElement) {
| Some(elm) =>
  D.EventTarget.addEventListener(
    "change",
    optionChangeHandler,
    D.Element.asEventTarget(elm),
  )
| None => ()
};

NOTE:

I also tried this - using addSelectEventListener - but nothing was triggered:

switch (optionElement) {
| Some(elm) =>
  D.EventTarget.addSelectEventListener(
    optionChangeHandler,
    D.Element.asEventTarget(elm),
  )
| None => ()
};