dynamic list

by Laberwurschd

HTML

<form id="lister">
  <ul>
    <li>
      one
      <button name="remove-1" title="remove">remove</button>
    </li>
    <li>
      two
      <button name="remove-2" title="remove">remove</button>
    </li>
    <li>
      <label>
      new list item:
      <input name="new_li">
    </label>
      <button name="add">add</button>
    </li>
  </ul>
</form>

CSS

[name^="remove"] {
  background: #fee;
  border: 1px solid red;
  border-radius: 0.2em;
  color: red;
  cursor: pointer;
  opacity: 0.5;
  overflow: hidden;
  padding: 0 0 0 1em;
  position: relative;
  width: 0em;
}

[name^="remove"]::before {
  content: "x";
  position: absolute;
  left: 25%;
}

[name^="remove"]:hover {
  opacity: 1;
}

[name="add"] {
  background: #efe;
  border: 1px solid green;
  border-radius: 0.2em;
  color: green;
  cursor: pointer;
  font-size: 120%;
  font-weight: bold;
  opacity: 0.5;
  overflow: hidden;
  padding: 0 0 0 1em;
  position: relative;
  width: 0em;
}

[name="add"]::before {
  content: "+";
  position: absolute;
  left: 24%;
}

JavaScript

(function() {

  let form = document.getElementById("lister");

  /* collect all remove buttons
   * and determine current counter value */
  let counter = 0;

  [].slice.call(
    document.querySelectorAll('#lister [name^="remove-"]')
  ).forEach(function(el) {
    let c = el.name.replace(/\D/g, "");
    console.log("c: " + c);
    if (counter < c) {
      counter = c;
    }
  });

  // make <form> unsubmittable
  form.addEventListener(
    "submit",
    function(ev) {
      ev.stopPropagation();
      ev.preventDefault();
      return false;
    }
  );

  // only react on clicked buttons
  form.addEventListener(
    "click",
    function(ev) {

      // element is a <button>?
      if (ev.target.tagName &&
        ev.target.tagName.match(/^button$/i)
      ) {

        // remove button?
        if (ev.target.name.match(/^remove-/)) {
          ev.target // <button>
            .parentNode // <li>
            .parentNode // <ul>
            .removeChild(ev.target.parentNode);
        }

        // add button?
        if (ev.target.name == "add") {
          let button = document.createElement("button");
          let input = form.querySelector('[name="new_li"]');
          let newLi = document.createElement("li");

          // add new <li> before our last one
          input
            .parentNode // <label>
            .parentNode // <li>
            .parentNode // <ul>
            .insertBefore(
              newLi,
              input.parentNode.parentNode
            );

          // insert data into new <li>
          newLi.appendChild(
            document.createTextNode(input.value + " ")
          );

          button.appendChild(
            document.createTextNode("remove")
          );

          counter++;

          button.setAttribute(
            "name",
            "remove-" + counter
          );

          button.setAttribute(
            "title",
            "remove"
          );

          // insert a remove button
         ...