user9165701
user9165701

Reputation:

Dynamic form with JavaScript and HTML

I'm trying to build a page form in HTML with a button that allows you to add and remove fields dynamically. In particular, I want on click 3 new field.

I follow indications on W3C and StackOverflow but my code doesn't work. In added in Safari with developer instruments I don't get any kind of error.

This is my HTML code:

var numWriters;

function isNumberKey(event) {
  var code = event.which || event.keyCode;
  if (code > 31 && (code < 48 || code > 57))
    return false;
  return true;
}

function resetNumWriters() {
  numWriters = 1;
}

function addWriter() {
  numWriters++;

  var divWriters = document.getElementById("containerWriters");
  var ul = document.createElement("ul");
  var liName = document.createElement("li");

  var labelName = document.createElement("label");
  var strongName = document.createElement("strong");
  strongName.InnerHTML = "Writer's name";
  var inputTextName = document.createElement("input");
  inputTextName.setAttribute("type", "text");
  inputTextName.setAttribute("name", "writerName" + numWriters);

  divWriters.appendChild(ul);
  ul.appendChild(liName);
  liName.appendChild(labelName);
  labelName.appendChild(strongName);
  liName.appendChild(inputTextName);

  var liSurname = document.createElement("li");
  var labelSurname = document.createElement("label");
  var strongSurname = document.createElement("strong");
  strongSurname.InnerHTML = "Writer's surname";
  var inputTextSurname = document.createElement("input");
  inputTextSurname.setAttribute("type", "text");
  inputTextSurname.setAttribute("name", "writerSurname" + numWriters);

  ul.appendChild(liSurname);
  liSurname.appendChild(labelSurname);
  labelSurname.appendChild(strongSurname);
  liSurname.appendChild(inputTextSurname);

  var liDateOfBirth = document.createElement("li");
  var labelDateOfBirth = document.createElement("label");
  var strongDateOfBirth = document.createElement("strong");
  strongDateOfBirth.InnerHTML = "Writer's dateOfBirth";
  var inputDateOfBirth = document.createElement("input");
  inputDateOfBirth.setAttribute("type", "date");
  inputDateOfBirth.setAttribute("name", "writerDateOfBirth" + numWriters);

  ul.appendChild(liDateOfBirth);
  liSurname.appendChild(labelDateOfBirth);
  labelDateOfBirth.appendChild(strongDateOfBirth);
  liDateOfBirth.appendChild(inputDateOfBirth);
}
<form class="formSpaceDataProduct" action="addBook" method="POST">
  <fieldset>
    <legend> Insert the book data </legend>
    <ul>
      <li>
        <label> <strong>Title:</strong> </label>
        <input type="text" name="Title" placeholder="Title of book" maxlength="50" required></input>
      </li>
      <li>
        <label> <strong>Quantity:</strong> </label>
        <input type="text" name="Quantity" placeholder="Max quantity in stock can be 999" maxlength="3" pattern="[0-9]{1,3}" onkeydown="return isNumberKey(event)" required></input>
      </li>
      <li>
        <label> <strong>Year of publication:</strong> </label>
        <input type="text" name="yearOfPublication" placeholder="Year of publication" maxlength="4" pattern="[0-9]{1,4}" onkeydown="return isNumberKey(event)" required></input>
      </li>
      <li>
        <label> <strong>Genre:</strong> </label>
        <select name="Genre">
          <option value="Select">Select</option>
          <option value="History">History</option>
          <option value="Fantasy">Fantasy</option>
          <option value="Child">Child</option>
          <option value="Art">Art</option>
          <option value="Music">Music</option>
          <option value="Thriller">Thriller</option>
          <option value="Travel">Travel</option>
          <option value="Biography">Biography</option>
          <option value="Poetry">Poetry</option>
          <option value="Romance">Romance</option>
          <option value="Science">Science</option>
        </select>
      </li>
      <li>
        <label> <strong>Number of pages:</strong> </label>
        <input type="text" name="numPages" placeholder="Max length: 99.999 pages" maxlength="5" pattern="[0-9]{1,5}" onkeydown="return isNumberKey(event)" required></input>
      </li>
      <li>
        <label> <strong>ISBN:</strong> </label>
        <input type="text" name="ISBN" placeholder="A 13-digit numric code" maxlength="13" pattern="[0-9]{13}" onkeydown="return isNumberKey(event)" required></input>
      </li>
      <li>
        <label> <strong>Publisher:</strong> </label>
        <input type="text" name="publisher" placeholder="The name of the publishing house" maxlength="30" required></input>
      </li>
      <li>
        <label> <strong>Writer's name:</strong> </label>
        <input type="text" name="writerName1" placeholder="The name of the Writer" maxlength="20" required></input>
      </li>
      <li>
        <label> <strong>Writer's surname:</strong> </label>
        <input type="text" name="writerSurname1" placeholder="The surname of the Writer" maxlength="20" required></input>
      </li>
      <li>
        <label> <strong>Writer's date of birth:</strong> </label>
        <input type="date" name="writerDateOfBirth1" required></input>
      </li>
    </ul>

    <div id="containerWriters">
      <button type="button" id="addWriter" onclick="addWriter"> Add Writer </button>
    </div>

    <!--Submit all data -->
    <input type="submit" value="Insert" id="submit"></input>
  </fieldset>
</form>

In my JS code the variable numWriters would like to be used to count how many writers are already added at the form. This because I need the attribute "name" of each field of each writer different from previous. I want reset this variable in each page that include this javascript file. Is it correct?

Thank a lot.

Upvotes: 1

Views: 115

Answers (1)

balexandre
balexandre

Reputation: 75083

First of all Welcome to Stackoverflow! :)

regarding your code:

  • in your button tag, to call a function, the onclick event must specify a function and all you're specifying is a string. you should change onclick="addWriter" into onclick="addWriter()"

  • because of the name of your function, please change the button id into something else, for example <button type="button" id="btnAddWriter" ...

  • you also need to understand that the way of appending elements is very important, if you create a label, and a strong and then set the innerHTML of your strong tag, but append the label first, the strong will have no text...

  • you're also forgetting to set your global variable, so I will just assume that you call resetNumWriters() on page load...

  • for last, and to avoid DRY (Don't Repeat Yourself) I would suggest a code like:

<script>
    var numWriters;

    function isNumberKey(event) {
      var code = event.which || event.keyCode;
      if (code > 31 && (code < 48 || code > 57))
        return false;
      return true;
    }

    function resetNumWriters() {
      numWriters = 1;
    }

    function addTextField(title, numWriters) {
      console.log('addTextField ' + numWriters);
      var liName = document.createElement("li");
      var labelName = document.createElement("label");
      var strongName = document.createElement("strong");
      strongName.innerHTML = title + ":&nbsp;";
      var inputTextName = document.createElement("input");
      inputTextName.setAttribute("type", "text");
      inputTextName.setAttribute("name", "writerName" + numWriters);

      labelName.appendChild(strongName);
      liName.appendChild(labelName);
      liName.appendChild(inputTextName);

      return liName;
    }

    function addBirthdayField(title, numWriters) {
      console.log('addBirthdayField ' + numWriters);
      var liDateOfBirth = document.createElement("li");
      var labelDateOfBirth = document.createElement("label");
      var strongDateOfBirth = document.createElement("strong");
      strongDateOfBirth.innerHTML = title + ":&nbsp;";
      var inputDateOfBirth = document.createElement("input");
      inputDateOfBirth.setAttribute("type", "date");
      inputDateOfBirth.setAttribute("name", "writerDateOfBirth" + numWriters);

      labelDateOfBirth.appendChild(strongDateOfBirth);
      liDateOfBirth.appendChild(labelDateOfBirth);
      liDateOfBirth.appendChild(inputDateOfBirth);

      return liDateOfBirth;
    }

    function addWriter() {
      numWriters++;
      console.log('adding Writter ' + numWriters);

      var divWriters = document.getElementById("containerWriters");
      var ul = document.createElement("ul");

      var labelName = addTextField("Writer's name", numWriters);
      var labelSurname = addTextField("Writer's surname", numWriters);
      var labelBirthday = addBirthdayField("Writer's date of birth", numWriters);

      ul.appendChild(labelName);
      ul.appendChild(labelSurname);
      ul.appendChild(labelBirthday);

      divWriters.appendChild(ul);
    }

    resetNumWriters();
</script>

edited August 29th, 2019 - added remove writer code

  • creating a button and styling it in <style> that will remove the ul
  • extrated addLabelField to it's own function
<style>
    fieldset { width: 480px; }
    ul button { position: relative; float: right; }
</style>

<script>
    var numWriters;

    function isNumberKey(event) {
      var code = event.which || event.keyCode;
      if (code > 31 && (code < 48 || code > 57))
        return false;
      return true;
    }

    function resetNumWriters() {
      numWriters = 1;
    }

    // added function
    function addLabelField(title) { 
      var label = document.createElement("label");
      var strong = document.createElement("strong");
      strong.innerHTML = title + ":&nbsp;";

      label.appendChild(strong);
      return label;
    }

    function addTextField(title, numWriters) {
      console.log('addTextField ' + numWriters);

      var liName = document.createElement("li");
      var labelName = addLabelField(title);

      var inputTextName = document.createElement("input");
      inputTextName.setAttribute("type", "text");
      inputTextName.setAttribute("name", "writerName" + numWriters);

      liName.appendChild(labelName);
      liName.appendChild(inputTextName);

      return liName;
    }

    function addBirthdayField(title, numWriters) {
      console.log('addBirthdayField ' + numWriters);

      var liDateOfBirth = document.createElement("li");
      var labelDateOfBirth = addLabelField(title);

      var inputDateOfBirth = document.createElement("input");
      inputDateOfBirth.setAttribute("type", "date");
      inputDateOfBirth.setAttribute("name", "writerDateOfBirth" + numWriters);

      liDateOfBirth.appendChild(labelDateOfBirth);
      liDateOfBirth.appendChild(inputDateOfBirth);

      return liDateOfBirth;
    }

    function addWriter() {
      numWriters++;
      console.log('adding Writter ' + numWriters);

      var divWriters = document.getElementById("containerWriters");

      // added button
      var btn = document.createElement("button");
      btn.innerHTML = "x";
      btn.setAttribute("onclick", "removeWriter("+ numWriters + ")");
      btn.setAttribute("title", "remove this writer");

      var ul = document.createElement("ul");
      ul.setAttribute("data-writter-id", numWriters);

      var labelName = addTextField("Writer's name", numWriters);
      var labelSurname = addTextField("Writer's surname", numWriters);
      var labelBirthday = addBirthdayField("Writer's date of birth", numWriters);

      ul.appendChild(btn);
      ul.appendChild(labelName);
      ul.appendChild(labelSurname);
      ul.appendChild(labelBirthday);

      divWriters.appendChild(ul);
    }

    function removeWriter(id) {
        document.querySelectorAll('ul[data-writter-id="' + id + '"]')[0].remove();
    }

    resetNumWriters();
</script>

You can find a full example on Fiddle - https://jsfiddle.net/balexandre/5k9rhyxo/3

Upvotes: 1

Related Questions