How to pass the id to the exclude function

4

I'm creating a to-do list, I can create fields with tasks, and elements with javascript, but when I click the close button, the only field that disappears is the last one. I put the elements created in an array as an object and assign a value to each created array, but I can not pass this value to the delete function so that the button excludes the entire field. What can I do?

var myNodelist = document.getElementsByTagName("LI");
var index = 0;
var array = [];

for (var i = 0; i < myNodelist.length; i++) {
  var span = document.createElement("SPAN");
  var txt = document.createElement("button");
  var xis = document.createTextNode("\u00D7");

  span.appendChild(txt);
  txt.appendChild(xis);
  txt.className = "close";
  myNodelist[i].appendChild(txt);

}


var close = document.getElementsByClassName("close");
for (var i = 0; i < close.length; i++) {
  close[i].onclick = function() {
    var div = this.parentElement;
    div.style.display = "none";
  }
}

function newElement() {

  var li = document.createElement("input");
  var ul = document.createElement("input");
  var done = document.createElement("input");
  done.setAttribute("type", "checkbox");
  var inputText = document.getElementById("myInput").value;
  var inputDate = document.getElementById("time").value;

  done.className = "checkIn";
  li.value = inputText;
  li.className = "valor";
  ul.value = inputDate;
  ul.className = "data";

  var span = document.createElement("SPAN");
  var txt = document.createElement("button");
  var xis = document.createTextNode("\u00D7");

  span.appendChild(txt);
  txt.appendChild(xis);
  txt.className = "close";

  if (inputText === '') {
    alert("Você precisa digitar algo primeiro!");
  } else {
    document.getElementById("recent").appendChild(done).style.width = "20px";
    document.getElementById("recent").appendChild(li);
    document.getElementById("recent").appendChild(ul).style.width = "90px";
    document.getElementById("recent").appendChild(span);

  }

  array.push({
    inputtexto: li,
    inputdata: ul,
    close: txt
  })
  index++;

  for (var i = 0; i < close.length; i++) {
    close[i].onclick = function() {
      var div = this.parentNode;
      div.style.display = "none";
      done.style.display = "none";
      li.style.display = "none";
      ul.style.display = "none";
    }
  }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <form method="POST" action="">
    <label for="add-task">Título:</label>
    <input type="text" id="myInput" name="titulo">
    <label for="date">Prazo:</label>
    <input type="date" id="time" name="data" /><br><br>
    <span onclick="newElement();" class="addBtn" id="newtask" style="cursor:pointer">Add</span>
  </form>
  <div id="recent" class="recent">

  </div>
</body>

</html>
    
asked by anonymous 30.10.2017 / 13:34

2 answers

1
  • The biggest problem, as @DvD has already said is the fact that there is a missing html element to encompass each new line that is inserted, because the fields are inserted in a way, so it does not have any parent elements group them together. This makes it harder to hide.
  • The code you have before the newElement function is not necessary because it attempts to add elements based on the amount of <li> of the document, but there are none.
  • Each time you add a new element to the html you do not need a for to assign all the functions of click of closes , but only that of the element that was added.
  • You have a closures problem in:

     for (var i = 0; i < close.length; i++) {
         close[i].onclick = function() {
    

    Because i will end up not having scope of for and all closes will refer to the last i . Consider the following verifiable example of the problem:

    const spans = document.querySelectorAll(".s");
    
    for (var i = 0; i < spans.length; ++i){
      spans[i].onclick = function(){
        console.log("click no span numero " + i);
      }
    }
    Clique nos números que se seguem:
    <span class="s">1</span>
    <span class="s">2</span>
    <span class="s">3</span>
    <span class="s">4</span>
    <span class="s">5</span>

Here you can clearly see that i does not have the scope of for and ends up being the same for all elements. In addition it is in the value in which it left the for which is 5 and only we have spans co% from% to 0 .

At this point one of the simplest ways to resolve this problem is to declare 4 with i , which guarantees the scope of let , and causes closure to function as expected: / p>

const spans = document.querySelectorAll(".s");

for (let i = 0; i < spans.length; ++i){
  spans[i].onclick = function(){
    console.log("click no span numero " + i);
  }
}
Clique nos números que se seguem:
<span class="s">1</span>
<span class="s">2</span>
<span class="s">3</span>
<span class="s">4</span>
<span class="s">5</span>

By matching these details your code would look like this:

var index = 0;
var array = [];

//obter o elemento do html apenas uma vez
const recent = document.getElementById("recent"); 

function newElement() {
  var li = document.createElement("input");
  var ul = document.createElement("input");
  var done = document.createElement("input");
  done.setAttribute("type", "checkbox");
  var inputText = document.getElementById("myInput").value;
  var inputDate = document.getElementById("time").value;

  done.className = "checkIn";
  li.value = inputText;
  li.className = "valor";
  ul.value = inputDate;
  ul.className = "data";

  var span = document.createElement("SPAN");
  var txt = document.createElement("button");
  var xis = document.createTextNode("\u00D7");
  var newdiv = document.createElement("div");

  span.appendChild(txt);
  txt.appendChild(xis);
  txt.className = "close";

  if (inputText === '') {
    alert("Você precisa digitar algo primeiro!");
  } else {
    //todos os elementos são adicionados ao novo div que os agrupa
    newdiv.appendChild(done).style.width = "20px";
    newdiv.appendChild(li);
    newdiv.appendChild(ul).style.width = "90px";
    newdiv.appendChild(span);
    recent.appendChild(newdiv); //novo div adicionado ao recent
  }

  array.push({
    inputtexto: li,
    inputdata: ul,
    close: txt
  });
  index++;
  
  //clique do close apenas definido para o elemento adicionado
  txt.onclick = function() {
      this.parentNode.parentNode.style.display="none";
  }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <form method="POST" action="">
    <label for="add-task">Título:</label>
    <input type="text" id="myInput" name="titulo">
    <label for="date">Prazo:</label>
    <input type="date" id="time" name="data" /><br><br>
    <span onclick="newElement();" class="addBtn" id="newtask" style="cursor:pointer">Add</span>
  </form>
  <div id="recent" class="recent">

  </div>
</body>

</html>

However, and just as I had already said in comments, building new html gets much simpler with strings. These strings store all the html structure to add already with attributes and classes, and it is applied directly in for .

Example with innerHTML and strings :

const inputText = document.getElementById("myInput");
const inputDate = document.getElementById("time");
const recent = document.getElementById("recent");

function newElement() {
  if (inputText.value === '') {
    alert("Você precisa digitar algo primeiro!");
    return;
  }
  
  let newHtml = '<div class="linha">
                   <input type="checkbox" class="checkIn" style="width:20px;">
                   <input type="text" value="${inputText.value}">
                   <input type="text" value="${inputDate.value}" style="width:90px;">               
                   <span><button class="close">\u00D7</button></span>
                 </div>';
   recent.innerHTML += newHtml;
   
   for (let l of document.querySelectorAll(".linha .close")){
      l.onclick = function() {
        this.parentNode.parentNode.style.display="none";
      }
   }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <form method="POST" action="">
    <label for="add-task">Título:</label>
    <input type="text" id="myInput" name="titulo">
    <label for="date">Prazo:</label>
    <input type="date" id="time" name="data" /><br><br>
    <span onclick="newElement();" class="addBtn" id="newtask" style="cursor:pointer">Add</span>
  </form>
  <div id="recent" class="recent">

  </div>
</body>

</html>

In this last case, as innerHTML is applied directly to innerHTML , it is necessary to re-apply events from <div id="recente"> to all lines.

    
31.10.2017 / 02:38
1

The right thing is for you to create a container (or wrapper ) (a div or a span , for example) for each item added. In the way you are doing, the elements go without their own reference. See below the structure of how the items are added:

<div id="recent" class="recent">
  checkbox
  input texto
  input datepicker
  <span>
    botao X
  </span>

  checkbox
  input texto
  input datepicker
  <span>
    botao X
  </span>
</div>

See that the items, which should belong to the same group, have as common reference only the parent id="recent" , making the work complicated because I can not select the child elements I want. >

As mentioned, create a div to group the elements, thus:

<div id="recent" class="recent">
  <div class="itens">
    checkbox
    input texto
    input datepicker
    <span>
      botao X
    </span>
  </div>

  <div class="itens">
    checkbox
    input texto
    input datepicker
    <span>
      botao X
    </span>
  </div>
</div>

I made the commented changes in the function below:

function newElement() {
  var li = document.createElement("input");
  var ul = document.createElement("input");
  var done = document.createElement("input");
  var lista = document.createElement("div"); // criar uma div para agrupar os itens
  lista.setAttribute("class", "itens"); // atribuí uma classe à div
  done.setAttribute("type", "checkbox");
  var inputText = document.getElementById("myInput").value;
  var inputDate = document.getElementById("time").value;

  done.className = "checkIn";
  li.value = inputText;
  li.className = "valor";
  ul.value = inputDate;
  ul.className = "data";

  var span = document.createElement("SPAN");
  var txt = document.createElement("button");
  var xis = document.createTextNode("\u00D7");

  span.appendChild(txt);
  txt.appendChild(xis);
  txt.className = "close";

  if (inputText === '') {
    alert("Você precisa digitar algo primeiro!");
  } else {
    document.getElementById("recent").appendChild(lista); // adiciono a div à div-pai
    ultimo_item = document.getElementsByClassName("itens").length-1; // conto quantas divs possui e subtraio por 1 para pegar o index, que começa com 0
    document.getElementsByClassName("itens")[ultimo_item].appendChild(done).style.width = "20px"; // daqui pra baixo eu adiciono os elementos dentro da div
    document.getElementsByClassName("itens")[ultimo_item].appendChild(li);
    document.getElementsByClassName("itens")[ultimo_item].appendChild(ul).style.width = "90px";
    document.getElementsByClassName("itens")[ultimo_item].appendChild(span);

  }

  array.push({
    inputtexto: li,
    inputdata: ul,
    close: txt
  })
  index++;

  for (var i = 0; i < close.length; i++) {
    close[i].onclick = function() {
      var div = this.parentNode.parentNode; // seleciono o avô do span que oculta o item
      div.style.display = "none"; // oculto a div
    }
  }
}
    
30.10.2017 / 17:01