DEV Community

Cover image for How you'd write a reactive calculator with x-HTML in 5 mins
chris-czopp
chris-czopp

Posted on • Edited on

How you'd write a reactive calculator with x-HTML in 5 mins

In this article you won't see the millionth way of writing a calculator with the tools that are well covered by many others. Instead, I'm going to show you how to do it with much less effort in a tool you probably haven't heard of yet. And it is a big deal since it automates and abstracts away frontend web app development by the ways you haven't seen elsewhere. And yeah, the calculator is a trivial app, yet it's a good example to present a few interesting concepts.

Alt Text

OK, enough of the intro, here are few steps to follow:

  1. Go to: https://ide.glue.codes.
  2. Create a new project.
  3. Write the below code, you can click preview to see changes as your'e typing.
  4. Export it to a self-contained app based on SolidJS and JSX.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta gc-as="navName" gc-name="Home">
  <title>Calculator</title>
</head>
<body>
  <div gc-as="layout">
    <div class="container">
      <div gc-as="slot" gc-name="content">

        <input-x type="number">
          <script>
            props.onChange = (e) => {
              uiSignals.numberA = parseInt(e.target.value)
            }
          </script>
        </input-x>

        <select-x>
          <script>
            props.onChange = (e) => {
              uiSignals.operator = e.target.value
            } 
          </script>
          <option value="+">+</option>
          <option value="-">-</option>
          <option value="*">*</option>
          <option value="/">/</option>
        </select-x>

        <input-x type="number">
          <script>
            props.onChange = (e) => {
              uiSignals.numberB = parseInt(e.target.value)
            }
          </script>
        </input-x>

        <span>=</span>

        <input-x type="number">
          <script>
            switch (uiSignals.operator) {
              case '-':
                props.value = uiSignals.numberA - uiSignals.numberB
                break

              case '*':
                props.value = uiSignals.numberA * uiSignals.numberB
                break

              case '/':
                props.value = uiSignals.numberA / uiSignals.numberB
                break

              case '+':
              default: 
                props.value = uiSignals.numberA + uiSignals.numberB
            }

          </script>
        </input-x>

      </div>
    </div>
  </div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

What just happened?

Well, the above code certainly wouldn't work if you dropped it into a regular HTML file. In a traditional way, you'd need to have a script below the document and manually query for an element and then update it. It could work in a small app which you don't plan to extend. But, if you need your UI to be reactive and at the same time maintainable you'd opt for some reactive framework or library. Perhaps JSX so your UI looks like HTML but it can be interpolated with dynamic data in a declarative fashion. That can be done beautifully with SolidJS and it will diff DOM at build-time as opposed to what many other frameworks/libraries do i.e. using Virtual DOM. It's all great but wouldn't it be cool to use HTML where possible and extend it to be reactive where necessary? This is exactly what you see in the code above.

It's a combination of extended tags and UI signals to mange the local state. At GlueCodes, we introduced extended tags which are named: tagName + '-x' and have an embedded <script> allowing you to access variables available in the scope where they have been placed. The scripts can assign to props variable to change props/attributes of the extended tag. In this case, you can see writing/reading uiSignals which holds some sort of observables and it'll update any props they are assigned to. What you see is a meta-framework abstracting away the signals. See SolidJS.

Notice the uiSignals are scoped to a slot/partial they are in and an HTML tag is told to be a slot by using one of many HTML directives:

<div gc-as="slot" gc-name="content">
...
</div>
Enter fullscreen mode Exit fullscreen mode

So, in addition to extended tags, you can make your HTML dynamic by using attribute directives as you would in modern web frameworks. When typing most of them you'll get notified to auto-create (if don't exist) required actions or to install a widget. The vocabulary here is simple, an attribute [gc-as] tells what it is and other [gc-*] attributes are parameters.

The above code can be split into 4 parts. An embedded script tag in each of the extended tag allows to modify their props e.g. register events or set a value on an input. It modifies only the props of its direct parent tag.

1) Capturing the first number:

<input-x type="number">
  <script>
    props.onChange = (e) => {
      uiSignals.numberA = parseInt(e.target.value)
    }
  </script>
</input-x>
Enter fullscreen mode Exit fullscreen mode

2) Capturing the operator:

<select-x>
  <script>
    props.onChange = (e) => {
      uiSignals.operator = e.target.value
    } 
  </script>
  <option value="+">+</option>
  <option value="-">-</option>
  <option value="*">*</option>
  <option value="/">/</option>
</select-x>
Enter fullscreen mode Exit fullscreen mode

3) Capturing the second number:

<input-x type="number">
  <script>
    props.onChange = (e) => {
      uiSignals.numberB = parseInt(e.target.value)
    }
  </script>
</input-x>
Enter fullscreen mode Exit fullscreen mode

4) Displaying the result of equation:

<input-x type="number">
  <script>
    switch (uiSignals.operator) {
      case '-':
        props.value = uiSignals.numberA - uiSignals.numberB
        break

      case '*':
        props.value = uiSignals.numberA * uiSignals.numberB
        break

      case '/':
        props.value = uiSignals.numberA / uiSignals.numberB
        break

      case '+':
      default: 
        props.value = uiSignals.numberA + uiSignals.numberB
    }

  </script>
</input-x>
Enter fullscreen mode Exit fullscreen mode

That's it about the UI signals. There is tons of features provided by GlueCodes Studio. Widgets, built-in app state management, implementation assistant and many more. The most importantly it runs in the browser and stores the project metadata and the exported SolidJS code on your hard drive!

Looking forward to see your feedback!

Top comments (0)