Creating Dynamic form content

Hello :slight_smile:

How do I create dynamic forms like below where you can Add and Remove content please see below example where you can add and remove spouse

https://www.vimo.com/health-insurance/health-insurance-quote.php

I currently have a classic ASP form and was wondering if I can do this with Javascript so I can extend the form with new content or remove it with a simpel click

Many many thanks
Andrew

Something to get you started. (The script should be external, of course.)

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Test</title>
    <style type="text/css">
      html {font:81.25&#37;/1.5 Verdana,sans-serif}
      input[type="text"] {margin:2px 0}
    </style>
  </head>
  <body>
    <form action="#">
      <fieldset id="products">
        <legend>Products</legend>
        <label for="p1">Product</label>
        <input type="text" name="p1" id="p1">
      </fieldset>
      <div>
        <input type="submit" value="Submit">
      </div>
    </form>
    <script type="text/javascript">
      (function () {
          var Products = {
              count:    1,

              init:     function () {
                            var fs = document.getElementById("products");
                            fs.appendChild(this.make("br", {id: "here"}));
                            var btn = fs.appendChild(this.make("input", {type: "button", value: "Add product"}));
                            btn.onclick = (function (_self) {
                                return function () {
                                    _self.add();
                                    return false;
                                };
                            })(this);
                        },

              add:      function () {
                            var id = "p" + ++this.count;
                            var br = document.getElementById("here");
                            br.parentNode.insertBefore(this.make("br"), br);
                            br.parentNode.insertBefore(this.make("label", {htmlFor: id}, "Product "), br);
                            br.parentNode.insertBefore(this.make("input", {type: "text", name: id, id: id}), br);
                            var btn = br.parentNode.insertBefore(this.make("input", {type: "button", value: "Remove", _id: id}), br);
                            btn.onclick = this.remove;
                        },

              remove:   function () {
                            var inp = document.getElementById(this._id);
                            var lbl = inp.previousSibling;
                            var br  = lbl.previousSibling;
                            this.parentNode.removeChild(br);
                            this.parentNode.removeChild(lbl);
                            this.parentNode.removeChild(inp);
                            this.parentNode.removeChild(this);
                            return false;
                        },

              make:     function (type, attrs, content) {
                            var element = document.createElement(type);
                            if (attrs !== undefined) {
                                for (var a in attrs) {
                                    element[a] = attrs[a];
                                }
                            }
                            if (content !== undefined) {
                                element.appendChild(document.createTextNode(content));
                            }
                            return element;
                        }
          };

          Products.init();
       })();
    </script>
  </body>
</html>

You’re welcome … :rolleyes:

Hi,

Thank you ever so much for the code sample you gave you, it was incredibly helpful. I am not a javascript programmer, but I made some attempts to modify this the way I need it to be.

I have a question, How do I now add in additional fields so they appear next to each other such as first name last name Age etc. I did try to do that but failed.

Below is the modified script you kindly sent me

Many Thanks
Andrew


    <fieldset id="Spouse">
     
     </fieldset>



   <script type="text/javascript">
     (function () {
         var Spouse = {
             count:    1,

             init:     function () {
                           var fs = document.getElementById("Spouse");
                           fs.appendChild(this.make("br", {id: "here"}));
                           var btn = fs.appendChild(this.make("input", {type: "button", value: "Add Spouse"}));
                           btn.onclick = (function (_self) {
                               return function () {
                                   _self.add();
                                   return false;
                               };
                           })(this);
                       },

             add:      function () {
                           var id = "p" + ++this.count;
                           var br = document.getElementById("here");
                           br.parentNode.insertBefore(this.make("br"), br);
                           br.parentNode.insertBefore(this.make("label", {htmlFor: id}, "First Name "), br);
                           br.parentNode.insertBefore(this.make("input", {type: "text", name: id, id: id}), br);
                           var btn = br.parentNode.insertBefore(this.make("input", {type: "button", value: "Remove", _id: id}), br);
                           btn.onclick = this.remove;
                       },

             remove:   function () {
                           var inp = document.getElementById(this._id);
                           var lbl = inp.previousSibling;
                           var br  = lbl.previousSibling;
                           this.parentNode.removeChild(br);
                           this.parentNode.removeChild(lbl);
                           this.parentNode.removeChild(inp);
                           this.parentNode.removeChild(this);
                           return false;
                       },

             make:     function (type, attrs, content) {
                           var element = document.createElement(type);
                           if (attrs !== undefined) {
                               for (var a in attrs) {
                                   element[a] = attrs[a];
                               }
                           }
                           if (content !== undefined) {
                               element.appendChild(document.createTextNode(content));
                           }
                           return element;
                       }
         };

         Spouse.init();
      })();
   </script>


Here’s a version that handles three fields. It should be fairly obvious where to add more fields (in the add() function). You may also have to modify the CSS if you add more fields.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Test</title>
    <style type="text/css">
      html {font:81.25&#37;/1.5 Verdana,sans-serif}
      input[type="text"] {margin:2px 0}
      .row {overflow:hidden}
      .row div {float:left; width:12em; margin-right:0.5em}
      .row div.btn {width:auto; margin:1.5em 0 0}
      .row label {display:block}
    </style>
  </head>
  <body>
    <form action="#">
      <fieldset id="Spouse">
        <legend>Spouse</legend>
        <div class="row">
          <div><label for="fn1">First name</label> <input type="text" name="fn1" id="fn1"></div>
          <div><label for="ln1">Last name</label> <input type="text" name="ln1" id="ln1"></div>
          <div><label for="a1">Age</label> <input type="text" name="a1" id="a1"></div>
        </div>
      </fieldset>
      <div>
        <input type="submit" value="Submit">
      </div>
    </form>
    <script type="text/javascript">
      (function () {
         var Spouse = {
             count:    1,

             init:     function () {
                           var fs = document.getElementById("Spouse");
                           var div = fs.appendChild(this.make("div", {id: "here"}));
                           var btn = div.appendChild(this.make("input", {type: "button", value: "Add Spouse"}));
                           btn.onclick = (function (_self) {
                               return function () {
                                   _self.add();
                                   return false;
                               };
                           })(this);
                       },

             add:      function () {
                           ++this.count;
                           var here = document.getElementById("here");
                           var row = here.parentNode.insertBefore(this.make("div", {className: "row", id: "row" + this.count}), here);
                           this.addField(row, "First Name ", "fn");
                           this.addField(row, "Last Name ",  "ln");
                           this.addField(row, "Age ",        "a");
                           var div = row.appendChild(this.make("div", {className: "btn"}));
                           var btn = div.appendChild(this.make("input", {type: "button", value: "Remove", _id: "row" + this.count}));
                           btn.onclick = this.remove;
                       },

             addField: function (parent, label, prefix) {
                           var div = parent.appendChild(this.make("div"));
                           div.appendChild(this.make("label", {htmlFor: prefix + this.count}, label));
                           div.appendChild(this.make("input", {type: "text", name: prefix + this.count, id: prefix + this.count}));
                       },

             remove:   function () {
                           var row = document.getElementById(this._id);
                           row.parentNode.removeChild(row);
                           return false;
                       },

             make:     function (type, attrs, content) {
                           var element = document.createElement(type);
                           if (attrs !== undefined) {
                               for (var a in attrs) {
                                   element[a] = attrs[a];
                               }
                           }
                           if (content !== undefined) {
                               element.appendChild(document.createTextNode(content));
                           }
                           return element;
                       }
         };

         Spouse.init();
       })();
    </script>
  </body>
</html>

Perfect Thanks, that was awesome !!!


I have another related question, that I need to ask here just in case it it requires specific coding that is unique to this way of creating text boxes dynamically

QUESTION
I see a number of websites that have text boxes such as Phone Number and inside the text box for phone number they have in light grey the words “e.g. 123-456-7890”, and the moment you click in the box the text vanishes!! how in the world is that done, and can that be done in this situation with the solutions you have so kindly provided.

Many thanks
Andrew

Personally, I think I would create all the fields for the ‘addable’ areas and just make the ‘add spouse’ toggle the fields display:block.

Hi

Thanks for your message, I think that is essentially how it will work, So Add Spouse displays all the required fields for the Spouse as a block

In my last post, I wanted to see if i can get the consumer to specify their (for example) Date of Birth with out having to put in a select of year, Month and day, but if I can guide them with the format such as DD/MM/YYY then it makes my job easier and the code less complex I think

R
Andrew

I would suggest checking out a Javascript datepicker. There are many variations of this script freely available.

It’s not a good idea from an accessibility point of view. I think this sort of information belongs in the <label>, not in the input field itself. But here’s one way to do it,

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Test</title>
    <style type="text/css">
      html {font:81.25%/1.5 Verdana,sans-serif}
      input.example {color:#999}
      #phone {width:10em}
    </style>
  </head>
  <body>
    <form action="#">
      <div>
        <label for="phone">Phone number:</label>
        <input type="text" id="phone" value="e.g., 123-456-7890" class="example">
        <input type="submit" value="Submit">
      </div>
    </form>
    <script type="text/javascript">
      (function () {
          var Example = {
              init:     function (id) {
                            var element = document.getElementById(id);
                            element.onfocus = this.remove;
                            element.onblur  = this.add;
                        },

              add:      function () {
                            if (this.value === "") {
                                this.value = this.defaultValue;
                                this.className = "example";
                            }
                        },

              remove:   function () {
                            if (this.value === this.defaultValue) {
                                this.value = "";
                                this.className = "";
                            }
                        },
          };

          Example.init("phone");
       })();
    </script>
  </body>
</html>

That wouldn’t work if you need to add an arbitrary number of fields or groups of fields.

I agree.

Many thanks, I much appreciate all your assistance and help

:slight_smile:

Hello,

Below is your code you posted, which i appreciate

How can I add a drop down list boxe for say Months of the year

Many thanks


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Test</title>
    <style type="text/css">
      html {font:81.25%/1.5 Verdana,sans-serif}
      input[type="text"] {margin:2px 0}
      .row {overflow:hidden}
      .row div {float:left; width:12em; margin-right:0.5em}
      .row div.btn {width:auto; margin:1.5em 0 0}
      .row label {display:block}
    </style>
  </head>
  <body>
    <form action="#">
      <fieldset id="Spouse">
        <legend>Spouse</legend>
        <div class="row">
          <div><label for="fn1">First name</label> <input type="text" name="fn1" id="fn1"></div>
          <div><label for="ln1">Last name</label> <input type="text" name="ln1" id="ln1"></div>
          <div><label for="a1">Age</label> <input type="text" name="a1" id="a1"></div>
        </div>
      </fieldset>
      <div>
        <input type="submit" value="Submit">
      </div>
    </form>
    <script type="text/javascript">
      (function () {
         var Spouse = {
             count:    1,
 
             init:     function () {
                           var fs = document.getElementById("Spouse");
                           var div = fs.appendChild(this.make("div", {id: "here"}));
                           var btn = div.appendChild(this.make("input", {type: "button", value: "Add Spouse"}));
                           btn.onclick = (function (_self) {
                               return function () {
                                   _self.add();
                                   return false;
                               };
                           })(this);
                       },
 
             add:      function () {
                           ++this.count;
                           var here = document.getElementById("here");
                           var row = here.parentNode.insertBefore(this.make("div", {className: "row", id: "row" + this.count}), here);
                           this.addField(row, "First Name ", "fn");
                           this.addField(row, "Last Name ",  "ln");
                           this.addField(row, "Age ",        "a");
                           var div = row.appendChild(this.make("div", {className: "btn"}));
                           var btn = div.appendChild(this.make("input", {type: "button", value: "Remove", _id: "row" + this.count}));
                           btn.onclick = this.remove;
                       },
 
             addField: function (parent, label, prefix) {
                           var div = parent.appendChild(this.make("div"));
                           div.appendChild(this.make("label", {htmlFor: prefix + this.count}, label));
                           div.appendChild(this.make("input", {type: "text", name: prefix + this.count, id: prefix + this.count}));
                       },
 
             remove:   function () {
                           var row = document.getElementById(this._id);
                           row.parentNode.removeChild(row);
                           return false;
                       },
 
             make:     function (type, attrs, content) {
                           var element = document.createElement(type);
                           if (attrs !== undefined) {
                               for (var a in attrs) {
                                   element[a] = attrs[a];
                               }
                           }
                           if (content !== undefined) {
                               element.appendChild(document.createTextNode(content));
                           }
                           return element;
                       }
         };
 
         Spouse.init();
       })();
    </script>
  </body>
</html>

The same way that you add the label and the input. Use the make() method in the Spouse object.

var sel = div.appendChild(this.make("select", {name: "m" + this.count}));
sel.appendChild(this.make("option", {value:"1"}, "January"));
sel.appendChild(this.make("option", {value:"2"}, "February"));
...

Then you’ll need to add the appropriate CSS to style things.

Thank you
Perfect