Как выполнить делегирование событий в объектно-ориентированном JS?

  1. У меня проблемы с захватом динамически созданных элементов DOM и
  2. Я не знаю, где должно происходить последующее делегирование события клика (то есть в моем основном файле .js или внутри класса пользовательского интерфейса).

Этот проект объектно-ориентированного обучения отправляет асинхронные HTTP-запросы с помощью выборки в API Punk и извлекает список пива на основе поискового запроса пользователя. Вывод не является жестко запрограммированным, а innerHTML списка создается динамически из данных API внутри класса с именем UI.

В app.js я обрабатываю обещания и использую ui.paint() для отображения пива на странице.

У каждого пива есть кнопка «купить», которая также создается динамически.

Я хочу захватить все кнопки, прокрутить их, прикрепить событие щелчка.

Я пробовал:

  1. захват кнопок в app.js с помощью queryselectorAll - не работает, возвращает пустой список узлов - этот селектор должен быть поднят, и на момент вызова кнопки явно еще не существуют - ЕСТЬ КАКОЙ-ТО АСИНХРОННЫЙ СПОСОБ решить это и дождаться возврата данных API и создания новых элементов? (примечание: когда у меня есть список сортов пива, я могу получить полный список узлов с помощью querySelectorAll в консоли браузера...)

  2. Я также попытался обернуть queryselectorAll внутри функции и вызвать эту функцию внутри функции события click, которая обрабатывает обещания. Это тоже не сработало.

  3. Я попытался поместить событие в app.js, а также в класс прототипа пользовательского интерфейса (который выглядел более аккуратно), но ни один из них не работает.

app JS
const ui = new UI();

document.getElementById('submit-button- name').addEventListener('click', (e) => {
e.preventDefault();

const newBeer = new Beer();

newBeer.getByName()
    .then(beerResult => {
        ui.paint(beerResult);
    })
    .catch(err => {
        console.log(err)
    });
});

const buyBtns = document.querySelectorAll('#buy-btn');

buyBtns.forEach((buyBtn) => {
   buyBtn.addEventListener('click', (e) => {
      ui.addToCart(e)
   });  
});
then here is the UI class, trying to pick up the event (I'm trying to grab the button that's in the last <a> tag of the innerHTML and push it in a cart array which I would later display on a separate page). 
class UI {
constructor() {
    this.productRow = document.getElementById('products-row');
} 

paint(beerResult) {
    let output = '';

    beerResult.forEach(beer => {
        output += 
        `<div class="card">
            <img id="beer-card-img" src="${beer.image_url}" alt="beer-image" class="card-image-top">
            <div class="card-body">
                <h5 class="card-title">${beer.name}</h5>
                <h6 class="tagline">${beer.tagline}.</h6>
                <p id="description" class="card-text">${beer.description}</p>
                <p id="abv" class="card-text">ABV: ${beer.abv}</p>
                <p id="ibu" class="card-text">IBU: ${beer.ibu}</p>
                <p id="ph" class="card-text">PH: ${beer.ph}</p>
                <p id="first-brewed" class="card-text">First brewed: ${beer.first_brewed}</p>
                <a href="#" class="btn btn-outline-dark btn-sm">See details</a>
                <a href="#" id="buy-btn" class="btn btn-danger btn-sm">Buy</a>
            </div>
        </div>`
    });

    // console.log(output);

    this.productRow.innerHTML = output;
}

addToCart(e) {

    let cart = [];

    if (e.target.parentElement.parentElement.classList.contains('card')) {
        cart.push(e.target.parentElement.parentElement)
    }

    console.log(cart);
}

}

Сейчас ничего не происходит, когда я нажимаю «Купить». Я хочу, чтобы пиво помещалось в массив (как объекты) для последующего отображения на отдельной странице.

Спасибо за терпение, время и советы!


person Adam    schedule 03.04.2019    source источник


Ответы (1)


  • Имеет смысл создать прослушиватель событий при создании кнопки. Поэтому я бы поместил прослушиватель событий в класс пользовательского интерфейса.

  • Если вы используете document.createElement() для создания кнопки, вы можете сразу прикрепить обработчик. Вам не нужно querySelector()

  • Поскольку функция addToCart также находится в пользовательском интерфейсе, вы можете вызвать эту функцию и сразу же передать объект пива.

Это упрощенный пример кода:

class UI {

  paint(beerResult) {

    for(let b of beerResult) {
        let card = document.createElement("card")
        let buyButton = document.createElement("button")

        card.appendChild(buyButton)

        buyButton.addEventListener("click", (e) => {
            this.addToCart(b)
        })

        this.productRow.appendChild(card)
    }
  }

  addToCart(b) {
      console.log("added this beer to the cart: " + b.description)
  }
}

Приложение js

let ui = new UI()
ui.paint([{description:"a nice beer"},{description:"some beer"}])

А вот и рабочий JSFiddle

person Kokodoko    schedule 04.04.2019