2

How would you select items from the DOM using Reason. I'm using bs-webapi for the DOM bindings here is what I want to do:

let parent = document |> Document.querySelector(".parent");
let child = Element.querySelector(".child", parent);

However, BuckleScript complains because parent isn't of the right type. It says parent is of type option(Dom.element) and parent is expected to be Dom.element.t. I'm new to Reason and trying to learn. I don't understand what option(Dom.element) means or how to make something like the above code block work. Any help is greatly appreciated

Steven Scaffidi
  • 2,280
  • 1
  • 12
  • 14

1 Answers1

3

You need to unwrap the option variant, and we can do that with a switch and use the built-in None/Some variants.

You can find some documentation on the option variant here: https://reasonml.github.io/docs/en/newcomer-examples.html#using-the-option-type

Here is some more documentation on option: https://reasonml.github.io/docs/en/variant.html#option

To do this, you would change your code to something like this:

let parent = document |> Document.querySelector(".parent");
let child = switch (parent) {
  | Some(p) => switch (Element.querySelector(".child", p)) {
    | Some(c) => c
    | None => raise(Failure("Unable to find child selector"))
  }
  | None => raise(Failure("Unable to find parent selector"))
};

If you wanted to instead log to the console instead of fail, you would need to return a valid Dom.element.t, which could be something like this:

let emptyEl = document |> Document.createElement("noscript");
let parent = document |> Document.querySelector(".parent");
let child = switch (parent) {
  | Some(p) => switch (Element.querySelector(".child", p)) {
    | Some(c) => c
    | None => {
      Js.log("Unable to find child selector");
      emptyEl;
    }
  }
  | None => {
    Js.log("Unable to find parent selector");
    emptyEl;
  }
};

You would then want to check if your child element was a noscript to see if you found the child you were looking for.

Neil Kistner
  • 11,623
  • 2
  • 18
  • 17
  • This works. I was doing this; however, it was breaking because instead of raising a Failure I was trying to do a Js.log in the none. So types in the variant must match when using the option variant? How is a failure the same as Dom.element? Thank you for answering I'm just trying to get an understanding. – Steven Scaffidi Jan 12 '18 at 18:16
  • 1
    Yes, the types must still match. The reason `Js.log` didn't work is that it actually returns a `unit` type. Whereas the raise returns the type of `'a` which can be anything. So in the case above it would be a Dom.element.t. – Neil Kistner Jan 13 '18 at 02:48
  • Thanks again for the reply - that explains a lot. What if I didn't want want the program to break because I didn't find a parent? What if I just wanted to log that the parent wasn't found? I tried to but a Js.log below the switch and it didn't log because now I get an uncaught exception due to the Failure being raised. – Steven Scaffidi Jan 13 '18 at 04:07
  • I've updated the answer to show both methods and hopefully point you where you want to go. – Neil Kistner Jan 13 '18 at 15:54