Все кнопки теряют функцию после однократного использования - PullRequest
2 голосов
/ 11 мая 2019

У меня есть кнопка, которая отображает настраиваемое диалоговое окно.Если пользователь выбирает «отмена», диалоговое окно должно быть удалено из DOM, и никаких дальнейших действий не предпринимается.Если они нажимают «Start Delete», он должен продолжить с кодом.

Диалоговое окно отображается и скрывается правильно, однако после того, как я отменил и скрыл диалоговое окно, кнопка больше не работает, чтобы снова отобразить диалоговое окно.

Я создал всплывающий класс, которыйиспользует строку шаблона для отображения всплывающего окна, а затем я внедряю его в DOM.Всплывающее окно принимает обратный вызов в конструкторе, который я использую, чтобы скрыть всплывающее окно.

Пожалуйста, см. Следующую скрипту JS: https://jsfiddle.net/khgriffi259/vs6r5ake/13/

  class Popup {

    constructor(title, message, callback) {
      this.title = title;
      this.message = message;
      this.callback = callback;
      this.container = document.querySelector('body');
      this.result = '';
    }
  
    init() {
      const popup = `
          <div class="popup-wrapper">
              <div class="popup bg-white p-1">
                  <div class="popup-close">X</div>
                  <div class="popup-content ">
                      <h2 class="">${this.title}</h2>
                      <p class="p-1 my-2">${this.message}</p>
                      <div class="dialogue_buttons my-1">
                          <button class="btn popup-no" >Cancel</button>
                          <button class="btn btn-danger my-1 popup-yes" >Start Delete</button>
                      </div>
                  </div>
              </div>
          </div>  
      `;
      this.container.innerHTML += popup;
  
      this.container.querySelector('.popup-no').addEventListener('click', () => this.cancelListener());
      this.container.querySelector('.popup-yes').addEventListener('click', () => this.startListener());
  
    }
  
    cancelListener() {
      this.result = false;
    
        this.callback();
    //   if (this.callback !== undefined) {
    //     this.callback(this.result);
    //   }
    }
  
    startListener() {
      this.result  = true;
      if (this.callback !== undefined) {
        this.callback();
      }
    }
 

     
       getResult() {
         console.log(this.result) ;
        return this.result;
        }

  
  }

    //end of Popup Class

const button = document.querySelector('button');
button.addEventListener('click',  e => {
  if (e.target.tagName === 'BUTTON') {
    
    const confirmDelete = new Popup(
      'Delete', 
      'This will permanently delete this experience record.',
      ()=>{
        console.log('hello');
        let elem = document.querySelector('.popup-wrapper');
        elem.parentNode.removeChild(elem);
        
      }
    );
    confirmDelete.init();
     }
})
<button>
click me
</button>

Я ожидаю, что всплывающее окно будет скрыто, и кнопка будет функционировать для создания нового всплывающего окна, если пользователь снова нажмет кнопку.

Ответы [ 2 ]

3 голосов
/ 11 мая 2019

См. Ниже исправленную версию вашего кода.

Единственное изменение от

this.container.innerHTML += popup;

до

this.container.insertAdjacentHTML('beforeend', popup);

Причина, по которой исходный код дает сбой, заключается в том, что .innerHTML сериализует дерево DOM обратно в строку HTML, добавляет popup, затем присвоение .innerHTML повторяет весь процесс, воссоздавая все элементы с нуля. В качестве побочного эффекта ваш оригинальный слушатель click теряется, потому что он все еще привязан к старому элементу button. Присвоение .innerHTML означает, что вы получите совершенно новое дерево DOM.

Как документация для insertAdjacentHTML гласит:

Метод insertAdjacentHTML() интерфейса Element анализирует указанный текст как HTML или XML и вставляет результирующие узлы в дерево DOM в указанной позиции. Он не обрабатывает элемент, на котором он используется, и, следовательно, не разрушает существующие элементы внутри этого элемента. Это позволяет избежать дополнительного шага сериализации, делая его намного быстрее, чем прямой innerHTML манипуляция.

(Акцент мой.)

  class Popup {

    constructor(title, message, callback) {
      this.title = title;
      this.message = message;
      this.callback = callback;
      this.container = document.querySelector('body');
      this.result = '';
    }
  
    init() {
      const popup = `
          <div class="popup-wrapper">
              <div class="popup bg-white p-1">
                  <div class="popup-close">X</div>
                  <div class="popup-content ">
                      <h2 class="">${this.title}</h2>
                      <p class="p-1 my-2">${this.message}</p>
                      <div class="dialogue_buttons my-1">
                          <button class="btn popup-no" >Cancel</button>
                          <button class="btn btn-danger my-1 popup-yes" >Start Delete</button>
                      </div>
                  </div>
              </div>
          </div>  
      `;
      this.container.insertAdjacentHTML('beforeend', popup);
  
      this.container.querySelector('.popup-no').addEventListener('click', () => this.cancelListener());
      this.container.querySelector('.popup-yes').addEventListener('click', () => this.startListener());
  
    }
  
    cancelListener() {
      this.result = false;
    
        this.callback();
    //   if (this.callback !== undefined) {
    //     this.callback(this.result);
    //   }
    }
  
    startListener() {
      this.result  = true;
      if (this.callback !== undefined) {
        this.callback();
      }
    }
 

     
       getResult() {
         console.log(this.result) ;
        return this.result;
        }

  
  }

    //end of Popup Class

const button = document.querySelector('button');
button.addEventListener('click',  e => {
  if (e.target.tagName === 'BUTTON') {
    
    const confirmDelete = new Popup(
      'Delete', 
      'This will permanently delete this experience record.',
      ()=>{
        console.log('hello');
        let elem = document.querySelector('.popup-wrapper');
        elem.parentNode.removeChild(elem);
        
      }
    );
    confirmDelete.init();
     }
})
<button>
click me
</button>
1 голос
/ 11 мая 2019

Когда вы редактируете innerHTML из body, вы очищаете eventListener на button.

Я обновил скрипту до рабочей версии здесь https://jsfiddle.net/n5k9rsbe/6/

Есть 2 способа заставить это работать:

1 - Создать элемент контейнера и изменить его

<div id="container"></div>

JavaScript:

document.querySelector('#container').innerHTML = '...';

2 - ИспользоватьappendChild на body

const elem = document.createElement('div');
elem.innerHTML = popup
this.container.appendChild(elem)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...