DEV Community

J David Eisenberg
J David Eisenberg

Posted on

Manipulating the DOM with ReScript (Part 1)

Sometimes you will want to write a single-page web application, but you’d like to manipulate the DOM directly rather than use a framework like React.

The project we’re going to build will ask for parameters to two equations based on trigonometric functions and then draw a polar or Lissajous figure from those equations.

Blank canvas on left, input fields and Draw button on right

Setting up

Start by creating a ReScript project, renaming it, and going to its directory:

git clone https://github.com/rescript-lang/new-project
mv new-project domgraphs
cd domgraphs
Enter fullscreen mode Exit fullscreen mode

The src directory contains two files: Demo.res, the ReScript source file, and Demo.bs.js the generated JavaScript. (The bs stands for BuckleScript. BuckleScript has been rebranded as ReScript.) Remove the .bs.js file, and rename the source file:

rm src/Demo.bs.js
mv src/Demo.res src/DomGraphs.res
Enter fullscreen mode Exit fullscreen mode

Next, put the HTML into file src/index.html.

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>DOM Graphs</title>
    <style type="text/css">
      #canvas {
        width: 450px;
        float: left;
        border: 1px solid black;
        margin: 5px;
      }
    </style>
  </head>
  <body>
    <h1>DOM Graphs</h1>
    <canvas id="canvas" width="400" height="400">
      Your browser does not support the &lt;canvas&gt; element :(
    </canvas>
    <div>
      <p><input type="text" size="3" id="factor1"/>
      <select id="fcn1">
        <option value="sin">sin</option>
        <option value="cos">cos</option>
      </select>
      (
        <input type="text" size="3" id="theta1"/>
        &theta; +
        <input type="text" size="3" id="offset1"/>&deg;
      )</p>

      <p><input type="text" size="3" id="factor2"/>
      <select id="fcn2">
        <option value="sin">sin</option>
        <option value="cos">cos</option>
      </select>
      (
        <input type="text" size="3" id="theta2"/>
        &theta; +
        <input type="text" size="3" id="offset2"/>&deg;
      )</p>

      <p>
        Type of graph:
        <input type="radio" value="polar" name="graphType" id="polar"/>
          <label for="polar">Polar</label>
        <input type="radio" value="polar" name="graphType" id="lissajous"/>
          <label for="lissajous">Lissajous</label>
      </p>

      <p><button id="draw" value="draw">Draw</button></p>
    </div>
    <script type="text/javascript" src="DomGraphs.bs.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

The <script> element at the end gives the name of the JavaScript file containing the application code, which ReScript will generate from the DomGraphs.res file.

ReScript includes a Dom library for basic manipulation of the DOM, but for more power and convenience, you’ll want to use the bs-webapi library. Put the dependency for bs-webapi into the project’s bs-config.json file:

  "bs-dependencies": [
    "bs-webapi"
  ],
Enter fullscreen mode Exit fullscreen mode

Install bs-platform and bs-webapi:

npm install # installs the ReScript platform
npm install --save bs-webapi
Enter fullscreen mode Exit fullscreen mode

Finally, we need to have a bundler that will take the HTML file and JavaScript generated by the compiler and put it in one nice web application. In this article, I’m using parcel, because it works right out of the box and doesn’t require a lot of configuration. Install it globally so that you don’t need to duplicate it for every project.

npm install --global parcel-bundler
Enter fullscreen mode Exit fullscreen mode

Accessing the DOM

Let’s take a look at some of the modules in bs-webapi that you’ll use frequently, and those that we’ll use in this program.

Webapi
├── Canvas
│   ├── Webapi.Canvas.Canvas2d
├── Dom
│   ├── Webapi.Dom.Attr
│   ├── Webapi.Dom.ChildNode
│   ├── Webapi.Dom.Document
│   ├── Webapi.Dom.Element
│   ├── Webapi.Dom.Event
│   ├── Webapi.Dom.EventTarget
│   ├── Webapi.Dom.HtmlElement
│   ├── Webapi.Dom.HtmlInputElement
│   ├── Webapi.Dom.MouseEvent
│   ├── Webapi.Dom.Node
│   ├── Webapi.Dom.Text
│   └── Webapi.Dom.Window
Enter fullscreen mode Exit fullscreen mode

Let’s do a quick test of the JavaScript Window.alert() function. Replace the code in your DomGraphs.res file with this code:

let testAlert = Webapi.Dom.Window.alert("It works!", Webapi.Dom.window)
Enter fullscreen mode Exit fullscreen mode

The bs-webapi library is set up so that, most of the time, the element you’re working with (in this case, the window we’re using for the alert) is the last argument in the call.

Compile and bundle:

npm run build # or: bsb -make-world
parcel build src/index.html --public-url ./
Enter fullscreen mode Exit fullscreen mode

The parcel command specifies the entry point for the application (src/index.html) and the URL to use when serving the JavaScript—in this case, the same directory as the HTML (--public-url ./). This will locally install the cssnano package. You can specify the --no-minify flag to prevent this local install.

When these steps are complete, you’ll see a file named DomGraphs.bs.js, which is the JavaScript generated by ReScript, and a directory named dist that contains the bundled web app.

$ ls dist
DomGraphs.bs.5acda38d.js  DomGraphs.bs.5acda38d.js.map  index.html
Enter fullscreen mode Exit fullscreen mode

Every time you run parcel, it generates a new number to append to the bundled files based on the content of the files being processed. To avoid getting multiple different .js and .js.map files accumulating in your dist directory, you may want to remove the directory before rebuilding. Here is a bash script to do exactly that:

#!/bin/bash

npm run build # or bsb -make-world
status=$?
if test $status -eq 0
then
  rm -rf dist
  parcel build src/index.html src/*csv --public-url ./
fi
Enter fullscreen mode Exit fullscreen mode

If all has gone well, when you open the dist/index.html file in your browser, you’ll see an alert telling you that It works!

Now that everything is set up, it’s time to start writing the project code.

Top comments (0)