Обнаружить ошибку или каким должен быть код у начинающих JS?

203
20 апреля 2018, 15:32

Постепенно я решаю, не без помощи этого сайта, мелкие задачки для достижения решения одной большой задачи. Сейчас после написания около 50 строк кода, обнаружил ошибку, которую из-за малого опыта не могу определить.

  • Ошибка появляется, когда ввёл данные в textarea, далее 2 раза кликнул на кнопку отправить, а потом решил удалить появившиеся новые элементы нажатием на крестик. Одна вставка с элементами удаляется, другая нет.
  • Как писать JS правильно чтобы не возникало ошибок вроде моей?

  var submit = document.getElementById('submit');//записал в переменную кнопку "Отправить" 
  submit.addEventListener('click', handler);//добавляем событие и обработчик 
 
  function handler() {//начало функции-обработчика 
    var data = document.getElementById('in_1c').value;//получил и записал в переменную данные из textarea 
    var position = document.querySelector('.container');//записал в переменную родителя 
    //проверка, если поле textarea не пустое, то вставить и вывести данные, иначе сообщение об ошибке 
    if (data != 0) { 
        //вставка данных в конец родителя ".container" 
      position.insertAdjacentHTML('beforeEnd', ` 
        <div class="col-sm-12"> 
            <button type="button" class="close" aria-label="Close"> 
                  <span aria-hidden="true">&times;</span> 
            </button> 
            <ul class="data">${data.split(/\s/).map(m=>`<li>${m.toUpperCase()}</li>`).join('')}</ul> 
        </div> 
      `);//данные разделяются по пробелу регулярным выражением и изменяются другими методами 
        /*  
            1) .join() - объединяет все элементы массива (или массивоподобного объекта) в строку. 
            2) .toUpperCase() - возвращает значение строки с преобразованием в верхний регистр 
            3) .map() - создаёт новый массив с результатом вызова указанной функции для каждого элемента массива. 
            4) .split() - разбивает объект string на массив строк путём разделения указанной подстрокой или как в моем случае с помощью регулярного выражения 
        */ 
      var buttonClose = document.querySelector('button.close');//записал в переменную элемент кнопка 
      var parentElem = buttonClose.parentNode;//записал в переменную родительский элемент  
      buttonClose.addEventListener('click', removeChildren); //добавил событие на кнопку, присвоил обработчик "removeChildren" 
      function removeChildren() { //обработчик 
        while (parentElem.lastChild) { //цикл для удаления всех дочерних элементов 
          parentElem.removeChild(parentElem.lastChild); 
        } 
      } 
 
    } 
    else { //сообщение об ошибке 
      var warningEl = document.createElement('div'); //создание элемента 
      warningEl.setAttribute('class', 'warning'); //создание атрибута 
      var message = document.createTextNode('Пожалуйста, заполните соотвествующие поля для обработки!'); //создание текстового узла 
      warningEl.appendChild(message); //закрепляем текстовый узел в созданном элементе 
      var e = document.getElementsByClassName('container')[0]; //получил в перемиенную родительский элемент 
      e.appendChild(warningEl); //установка нового элемента на заданную позицию (по умолчанию ставится в конец) 
       
    } 
  }
.header { 
    margin-top: 30px; 
} 
.warning { 
    margin-top: 10px; 
    padding:10px; 
    font-size:2rem; 
    background: #F08080; 
    color: floralwhite; 
    border:1px solid red; 
} 
.data { 
    margin-top: 20px; 
    margin-left: -15px; 
    margin-right: -15px; 
    list-style-type: none; 
    padding:10px; 
    border:1px solid #ced4da; 
} 
.close { 
    position: relative; 
    right: -10px; 
    font-size: 2rem; 
} 
.close:focus {outline: none;}
<div class="container"> 
      <h2 class="header">Обработчик</h2> 
       <!--<form action="">--> 
             <div class="row"> 
                <div class="col-sm-6"><!--d-flex--> 
                    <div class="form-group"> 
                        <label for="in_1c">Номенклатура из 1С (например: RS-CS18AX/RU-18AX1)</label> 
                        <textarea name="" id="in_1c" cols="30" rows="20" class="form-control"></textarea> 
                        <p class="text-right mt-1"><input type="button" class="btn btn-secondary btn-sm" onClick="resetValue1();" value="Очистить"></p> 
                    </div> 
                </div> 
                <div class="col-sm-6"> 
                    <div class="form-group"> 
                        <label for="in_price">Номенклатура из прайса</label> 
                        <textarea name="" id="in_price" cols="30" rows="20" class="form-control"></textarea> 
                        <p class="text-right mt-1"><input type="button" class="btn btn-secondary btn-sm" onClick="resetValue2();" value="Очистить"></p> 
                    </div> 
                </div> 
                <div class="col-sm-12 text-left"><button type="submit" class="btn btn-primary" id="submit">Отправить</button></div> 
             </div> 
        <!--</form>--> 
</div>

Answer 1

Проблема в этой строчке:

var buttonClose = document.querySelector('button.close');

Когда вы добавляете вторую кнопку, этот селектор опять возвращает вам первую.

Можно сделать общий обработчик для кнопок удаления, вместо того чтоб каждый раз его вешать:

document.querySelector('.container').onclick = e => {
  if (e.target.matches('button.close')) {
    const parentElem = e.target.parentNode;
    while (parentElem.lastChild) { //цикл для удаления всех дочерних элементов
      parentElem.removeChild(parentElem.lastChild);
    }
  }
};
Answer 2

Родительские элементы у всех кнопок разные и их нужно не записывать в переменную, а вычислять внутри функции нажатия на кнопку. Вдобавок у вас определялась первая кнопка и ей присваивалась функция. А нужно было брать последнюю кнопку. Но раз вы код кнопки вставляете текстом по моему проще и обработчик вставить текстом.

var submit = document.getElementById('submit');//записал в переменную кнопку "Отправить" 
  submit.addEventListener('click', handler);//добавляем событие и обработчик 
 
function removeParent(e) { //обработчик 
  var parentElem = e.parentNode; //определяем родителя 
  parentElem.parentNode.removeChild(parentElem); //удаляем элемент 
} 
 
  function handler() {//начало функции-обработчика 
    var data = document.getElementById('in_1c').value;//получил и записал в переменную данные из textarea 
    var position = document.querySelector('.container');//записал в переменную родителя 
    //проверка, если поле textarea не пустое, то вставить и вывести данные, иначе сообщение об ошибке 
    if (data != 0) { 
        //вставка данных в конец родителя ".container" 
      position.insertAdjacentHTML('beforeEnd', ` 
        <div class="col-sm-12"> 
            <button type="button" class="close" aria-label="Close" onclick="removeParent(this);"> 
                  <span aria-hidden="true">&times;</span> 
            </button> 
            <ul class="data">${data.split(/\s/).map(m=>`<li>${m.toUpperCase()}</li>`).join('')}</ul> 
        </div> 
      `);//данные разделяются по пробелу регулярным выражением и изменяются другими методами 
        /*  
            1) .join() - объединяет все элементы массива (или массивоподобного объекта) в строку. 
            2) .toUpperCase() - возвращает значение строки с преобразованием в верхний регистр 
            3) .map() - создаёт новый массив с результатом вызова указанной функции для каждого элемента массива. 
            4) .split() - разбивает объект string на массив строк путём разделения указанной подстрокой или как в моем случае с помощью регулярного выражения 
        */ 
      //var buttonClose = document.querySelector('button.close');//тут вообще нужно брать последнюю кнопку а тут берется первая поэтому и проблема 
      //buttonClose.addEventListener('click', removeChildren); //добавил событие на кнопку, присвоил обработчик "removeChildren" 
    } 
    else { //сообщение об ошибке 
      var warningEl = document.createElement('div'); //создание элемента 
      warningEl.setAttribute('class', 'warning'); //создание атрибута 
      var message = document.createTextNode('Пожалуйста, заполните соотвествующие поля для обработки!'); //создание текстового узла 
      warningEl.appendChild(message); //закрепляем текстовый узел в созданном элементе 
      var e = document.getElementsByClassName('container')[0]; //получил в перемиенную родительский элемент 
      e.appendChild(warningEl); //установка нового элемента на заданную позицию (по умолчанию ставится в конец) 
       
    } 
  }
.header { 
    margin-top: 30px; 
} 
.warning { 
    margin-top: 10px; 
    padding:10px; 
    font-size:2rem; 
    background: #F08080; 
    color: floralwhite; 
    border:1px solid red; 
} 
.data { 
    margin-top: 20px; 
    margin-left: -15px; 
    margin-right: -15px; 
    list-style-type: none; 
    padding:10px; 
    border:1px solid #ced4da; 
} 
.close { 
    position: relative; 
    right: -10px; 
    font-size: 2rem; 
} 
.close:focus {outline: none;}
<div class="container"> 
      <h2 class="header">Обработчик</h2> 
       <!--<form action="">--> 
             <div class="row"> 
                <div class="col-sm-6"><!--d-flex--> 
                    <div class="form-group"> 
                        <label for="in_1c">Номенклатура из 1С (например: RS-CS18AX/RU-18AX1)</label> 
                        <textarea name="" id="in_1c" cols="30" rows="20" class="form-control"></textarea> 
                        <p class="text-right mt-1"><input type="button" class="btn btn-secondary btn-sm" onClick="resetValue1();" value="Очистить"></p> 
                    </div> 
                </div> 
                <div class="col-sm-6"> 
                    <div class="form-group"> 
                        <label for="in_price">Номенклатура из прайса</label> 
                        <textarea name="" id="in_price" cols="30" rows="20" class="form-control"></textarea> 
                        <p class="text-right mt-1"><input type="button" class="btn btn-secondary btn-sm" onClick="resetValue2();" value="Очистить"></p> 
                    </div> 
                </div> 
                <div class="col-sm-12 text-left"><button type="submit" class="btn btn-primary" id="submit">Отправить</button></div> 
             </div> 
        <!--</form>--> 
</div>

READ ALSO
Преобразование строки &ldquo;false&rdquo; в логическое false

Преобразование строки “false” в логическое false

Есть ли в JS метод наподобие parseFloat, который бы мог преобразовать строку "false" в Boolean false?

188
Как сделать так, чтобы переменная брала другое значение при вызове

Как сделать так, чтобы переменная брала другое значение при вызове

Есть такой телеграмм бот, который парсит сайт, забирает текстовую инфу и высылает при нажатой кнопкеИ он работает, но проблема в том, что в переменную...

168
Нет разрешения доступа к данным по api JS

Нет разрешения доступа к данным по api JS

Здравствуйте, возникла проблема с получением данных по apiДелаю запрос (убрал все лишнее для удобства):

204
проблема множественного добавления

проблема множественного добавления

Отслеживаю элементы iteminfo0_item_name и iteminfo1_item_name

174