从模板字符串/文字获取元素的ID

时间:2019-09-17 14:07:03

标签: javascript html firebase

我正在尝试使用addEventListener获取下面的按钮。如何返回null。 html是使用模板字符串从js呈现的。所以我想要实现的是addEventListener来删除模板字符串中的按钮。

// This is the template string
data.forEach(doc => {
        checkin = doc.data();
        card = `
        <div class="carousel-item fieldId" data-id="${doc.id}">
        <div class="col-12">
            <div class="card checkCard" style="margin: 0 auto;">
                <img src="${checkin.photo}" class="card-img-top" alt="...">
                <button type="submit" class="btn center delete">
                    <i class="material-icons" style="font-size: 1em;">delete_forever</i>
                </button>
                <div class="card-body">
                    <h5 class="card-title">${checkin.title}</h5>
                    <p class="card-text">${checkin.description}</p>
                </div>
            </div>
        </div>
        </div> 

        `;
        html += card;
    });

    checkinList.innerHTML = html;


//This is the delete button

const deleteContent = document.querySelector('.delete');
deleteContent.addEventListener('click', (e) => {
    // get current document ID
    console.log('hmm')
    e.stopPropagation();
    let id = $('.carousel-item').attr('data-id')
    db.collection("checkin").doc(id).delete().then(() => {
        console.log(id + "successfully deleted!");
        $('.carousel-item').attr('data-id')
    }).catch(function (error) {
        console.error("Error removing document: ", error);
    });
});

这是来自控制台的错误

Uncaught TypeError: Cannot read property 'addEventListener' of null
    at index.js:123
(anonymous) @ index.js:123

2 个答案:

答案 0 :(得分:1)

希望我已经概述了我所做的所有更改:

  1. 正如评论中指出的那样,ID必须是唯一的。通常,最好将类用作JavaScript(和CSS)挂钩。现在,许多人使用js-前缀来帮助维护代码时遵循HTML-> JS的逻辑,所以我建议这样做。
  2. document.querySelector('.delete')仅会得到一个元素-您需要在querySelectorAll,因为每个项目都有一个删除按钮。
  3. $('.carousel-item')是(我假设)一个jQuery函数调用。这将获取文档中的所有.carousel-item元素,而.attr('data-id')将仅获取第一个元素的属性。如果要在此处使用jQuery,则需要从$(e.target).parent('.carousel-item')之类的button元素上移DOM。但是,由于其他代码未使用jQuery,因此使用e.target.closest('.js-carousel-item'),imo将更加一致。然后,要获得data-id,我们可以轻松地使用element.dataset.id
  4. Don't use globals for this像骚动建议
  5. 我不确定您的示例中的data是否来自对db.collection('checkin').get()的调用,但是如果它是代码中的Promise,而不是快照本身,则在遇到以下情况时会遇到问题您的删除按钮代码未嵌套在then()回调中。
  6. 这更多是可选的旁注,但通过将其重构为使用async / await,您的代码可以变得更具可读性。

根据您在下面的示例中,我提供了一个有效的代码段来演示:

;(() => {
  // My attempt at a quick mock of Firebase to make this work as a snippet
  const db = {
    _collections: {
      'checkin': [
        {
          id: 1,
          photo: 'https://images.unsplash.com/photo-1508138221679-760a23a2285b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1267&q=80',
          title: 'airplane w/ trees',
          description: 'airplane on ground surrounded with trees',
        }, {
          id: 2,
          photo: 'https://images.unsplash.com/photo-1485550409059-9afb054cada4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80',
          title: 'head to head',
          description: 'minifigure head lot',
        },
      ],
    },
    collection(key) {
      const c = this._collections[key];
      const doc = (id) => ({
        id,
        data() {
          return c.find(o => o.id === id);
        },
        async delete() {
          const idx = c.findIndex(o => o.id === id);
          c.splice(idx, 1);
        },
      });
      return {
        doc,
        async get() {
          return c.map(o => o.id).map(doc);
        },
      };
    },
  }
  
  const render = () => {
    db.collection('checkin').get().then(snapshot => {
      const cards = snapshot.map(doc => {
        const checkin = doc.data();
        return `
          <div class="js-carousel-item carousel-item fieldId" data-id="${doc.id}">
            <div class="col-12">
              <div class="card checkCard" style="margin: 0 auto;">
                <img src="${checkin.photo}" class="card-img-top" alt="...">
                <button class="js-delete" type="submit" class="btn center">
                <i class="material-icons" style="font-size: 1em;">delete_forever</i>
                </button>
                <div class="card-body">
                  <h5 class="card-title">${checkin.title}</h5>
                  <p class="card-text">${checkin.description}</p>
                </div>
              </div>
            </div>
          </div>`;
      });
      document.querySelector('.js-checkin-list').innerHTML = cards.join('');
  
      // This is the delete button
      const deleteButtons = document.querySelectorAll('.js-delete');
      const deleteHandler = (e) => {
        e.stopPropagation();
        const el = e.target.closest('.js-carousel-item');
        const id = +el.dataset.id;
        db.collection('checkin').doc(id).delete().then(() => {
          console.log(`${id} successfully deleted!`);
        }).catch((error) => {
          console.error('Error removing document: ', error);
        })
        render();
      }
      deleteButtons.forEach(
        btn => btn.addEventListener('click', deleteHandler)
      );
    });
  };
  render();
})();
<div class="js-checkin-list carousel"></div>

答案 1 :(得分:0)

在字符串中使用onclick内联

例如

<!DOCTYPE html>

<html>

<head>
    <meta charset="UTF-8">
</head>

<body>
  <div id="parentDiv"></div>
</body>

<script>

let element = `<div id="childDiv" onclick="myFunction()">click here</div>`;

document.getElementById("parentDiv").innerHTML = element;


function myFunction() {
    console.log("works every time");
}
</script>
</html>

现在,子div插入了父div,并且具有onclick事件监听器

如果要循环播放,请不要在JS中循环播放addEventListener,也不要在模板文字中循环播放,换句话说,只需将其添加到字符串中即可,而不是额外的功能。

我刚刚对其进行了测试,并且..每次...时间

玩得开心!