Search code examples
javascripttypescriptinputhyperscript

How to stop hyperscript from overwriting my inputs ? Peryl


My problem is in an application form I am making where a lot of inputs needs to be filled. I am generating HTML using Hyperscript and I run into a problem where when I generate more elements into a page I lose information from inputs but only in a case when I delete some HTML positioned before the input and update the web. In example I have the original type of problem where I generated warning (saying to fill in information) before input where user gives information but as soon as the HTML is generated again without the warning the input is lost as well. Do you know any way how to keep the input and generate new HTML without moving the warning ? You can understand the problem better by looking up the example - you fill the input as the warning suggests and then you click to generate additional HTML but it deletes the input and you have to fill it again.

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <div id="app">

    </div>
    
    <!-- Peryl import -->
    <script src="https://unpkg.com/[email protected]/incremental-dom/dist/umd/incremental-dom.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/umd/hsml-h.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/umd/hsml-app.js"></script>
    <!-- end Peryl import -->
    <script>
        const state = {
            warning: "Please fill Temperature parameter",
            showDiv: false
        }

        function getWarning() {
            if (state.warning !== "") {
                return h("div#warning", {style:"color: red;"}, state.warning);
            }
        }

        function getDiv() {
            if (state.div) {
                return h("div", "The div is visible but input is gone");
            }
        }

        function view() {
            return [
                getWarning(),
                h("label", "Temperature"),
                h("input", {type:"text"}),
                h("button", {
                    on:["click", "showDiv"]
                }, "showDiv"),
                getDiv()
            ];
        }

        function dispatcher(app, action) {
            if (action.type === "showDiv") {
            state.warning = "";   // warning get's cleaned when it's filled
            state.div = !state.div;
            }
            app.update(); 
        }
        new HApp(state, view, dispatcher)
            .mount(document.getElementById("app"));
    </script>
  </body>
</html>

Solution

  • The described problem is given by rendering DOM nodes by incremental-dom engine under the HSML.

    This is similar problem like in rendering lists (for example in virtual dom in React) in which is best practice to mark list nodes by key to help rendering engine to manage node reordering.

    There is a list of DOM nodes under div#app node in the example. One of list nodes is input element. IDOM engine can't recognize node reordering so engine renders all new nodes and discards old ones when you shuffle elements. So input with its value is removed and replaced with new one containing empty value.

    To fix problem you have to mark input element with _key attribute to help rendering engine identify node during node shuffle like this:

    h("input", { _key: "some-input-key", type: "text" }).