未捕获(承诺)TypeError:无法读取null

时间:2020-10-06 15:05:01

标签: javascript

在indexedDb中,我的addEventListener得到了following error

like-unlike-button.js:46 Uncaught (in promise) TypeError: Cannot read property 'addEventListener' of null
    at Object._renderLiked (like-unlike-button.js:46)
    at Object._renderButton (like-unlike-button.js:21)
    at async Object.init (like-unlike-button.js:13)

我认为我在deleteRestaurant()中将错误的参数传递给了_renderLiked()

源代码:

like-unlike-button.js

import FavoriteResto from '../data/favorite-resto'
import { createLikeButton, createUnlikeButton } from '../templates/template-creator'

const LikeButtonInitiator = {
  async init ({ likeButtonContainer, url, resto }) {
    this._likeButtonContainer = likeButtonContainer
    this._resto = resto
    this._url = url

    await this._renderButton()
  },

  async _renderButton () {
    const { id } = this._resto
    const { url } = this._url

    if (await this._isRestaurantExist(id)) {
      this._renderLiked(id)
    } else {
      this._renderLike()
    }
  },

  async _isRestaurantExist (id) {
    const resto = await FavoriteResto.getRestaurant(id)
    return !!resto
  },

  _renderLike () {
    this._likeButtonContainer.innerHTML = createLikeButton()

    const likeButton = document.querySelector('#like-button')
    likeButton.addEventListener('click', async () => {
      await FavoriteResto.putRestaurant(this._resto.ikd)
      this._renderButton()
    })
  },

  _renderLiked () {
    this._likeButtonContainer.innerHTML = createUnlikeButton()

    const likeButton = document.getElementById('like-button')
    likeButton.addEventListener('click', async () => {
      await FavoriteResto.deleteRestaurant(this._url.id)
      this._renderButton()
    })
  }
}

export default LikeButtonInitiator

detail.js

import UrlParser from '../url/url-parser'
import RestaurantSource from '../data/restaurant-source'
import { createRestaurantDetail } from '../templates/template-creator'
import LikeButtonInitiator from '../tools/like-unlike-button'
import dateNow from '../tools/dateNow'

const Detail = {
  async render () {
    return `
    <h2 class="title">Detail Restaurant</h2>
    <div id="detail"></div>
    <div id="likeButtonContainer"></div>
    `
  },

  async afterRender () {
    const url = UrlParser.parseActiveUrlWithoutCombiner()
    const resto = await RestaurantSource.DetailResto(url.id)
    const restoDetail = document.querySelector('#detail')
    const restaurants = createRestaurantDetail(resto.restaurant)
    restoDetail.innerHTML = restaurants
    console.log(resto.restaurant)

    LikeButtonInitiator.init({
      likeButtonContainer: document.querySelector('#likeButtonContainer'),
      url,
      resto: {
        id: url.id,
        pictureId: resto.restaurant.pictureId,
        name: resto.restaurant.name,
        description: resto.restaurant.description,
        rating: resto.restaurant.rating,
        city: resto.restaurant.city
      }
    })

    const submitButton = document.querySelector('#input-submit')
    submitButton.addEventListener('click', () => {
      const inputName = document.querySelector('#input-name').value
      const inputReview = document.querySelector('#input-review').value
      const inputText = {
        id: url.id,
        name: inputName,
        review: inputReview,
        date: dateNow
      }

      RestaurantSource.PostReview(inputText)
      const updateUi = document.querySelector('.detail-review-grid')
      updateUi.innerHTML += `
        <div class="detail-review-card">
        <i class="fa fa-user-circle-o" aria-hidden="true"></i>
          <div class="detail-review-text">
            <p class="detail-review-name">${inputText.name}</p>
            <p class="detail-review-date">${inputText.date}</p>
            <p class="detail-review-reviewer">${inputText.review}</p>
          </div>
        </div>
      `
      document.querySelector('#input-name').value = ''
      document.querySelector('#input-review').value = ''
    })
  }
}

export default Detail


favorite-resto.js

import { openDB } from 'idb'
import CONFIG from './config'

const { DATABASE_NAME, DATABASE_VERSION, OBJECT_STORE_NAME } = CONFIG

const dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, {
  upgrade (database) {
    database.createObjectStore(OBJECT_STORE_NAME, { keyPath: 'id', autoIncrement: true })
  }
})

const FavoriteResto = {
  async getRestaurant (id) {
    return (await dbPromise).get(OBJECT_STORE_NAME, id)
  },
  async getAllRestaurant () {
    return (await dbPromise).getAll(OBJECT_STORE_NAME)
  },
  async putRestaurant (resto) {
    return (await dbPromise).put(OBJECT_STORE_NAME, resto)
  },
  async deleteRestaurant (id) {
    return (await dbPromise).delete(OBJECT_STORE_NAME, id)
  }
}

export default FavoriteResto

1 个答案:

答案 0 :(得分:0)

此template-creator.js 从'../data/config'导入CONFIG

const createRestaurantList = (restaurant) => `
  <div class="cards-item">
    <div class="card">
      <div class="card-image">
      <span class="label-rating fa fa-star"> ${restaurant.rating}</span>
      <span class="label-city fa fa-building-o"> ${restaurant.city}</span>
      <a href="${`/#/detail/${restaurant.id}`}" class="card-title">
      <img class="imagecard" alt="picture of restaurant" src="${CONFIG.BASE_URL_PHOTO}/${restaurant.pictureId}">
      </a>
      </div>
    <div class="card-content">
      <a href="${`/#/detail/${restaurant.id}`}" class="card-title">${restaurant.name}</a>
      <p class="card-text" maxlength="100">${restaurant.description}</p>
    </div>
  </div>
</div>
`

const createRestaurantDetail = (restaurant) => `
  <div class="detail-container">
    <div class="detail-card">
      <img class="detail-image" alt="picture of restaurant" src="${CONFIG.BASE_URL_PHOTO}/${restaurant.pictureId}">
      <div class="detail-text">
        <h2 class="detail-title">${restaurant.name}</h2>
        <p><i class="fa fa-star" aria-hidden="true"></i> ${restaurant.rating}</p>
        <p><i class="fa fa-map-marker" aria-hidden="true"></i> ${restaurant.address}, ${restaurant.city}</p>
        <p><i class="fa fa-cutlery" aria-hidden="true"></i> ${restaurant.categories
          .map((category) => `
          ${category.name}
          `
          ).join('')}
        </p>
        <p>${restaurant.description}</p>
      </div>
    </div>
  </div>
  <div class="detail-menus-container">
    <h2 class="detail-container-title">Menu</h2>
    <div class="detail-menus-flex">
    <ul class="detail-menus-foods">
    <h3><i class="fa fa-spoon" aria-hidden="true"></i> Foods</h3>${restaurant.menus.foods
          .map((food) => `
            <li class="detail-menus-items">${food.name}</li>
          `
          ).join('')}
    </ul>
    <ul class="detail-menus-drinks">
    <h3><i class="fa fa-glass" aria-hidden="true"></i> Drinks</h3>${restaurant.menus.drinks
          .map((drink) => `
            <li class="detail-menus-items">${drink.name}</li>
            `
          ).join('')}
    </ul>
    </div>
  </div>
  <div class="detail-review-container">
    <h2 class="detail-container-title">Consumer Reviews</h2>
    <div class="detail-review-grid">
      ${restaurant.consumerReviews
          .map((reviews) => `
          <div class="detail-review-card">
          <i class="fa fa-user-circle-o" aria-hidden="true"></i>
            <div class="detail-review-text">
              <p class="detail-review-name">${reviews.name}</p>
              <p class="detail-review-date">${reviews.date}</p>
              <p class="detail-review-reviewer">${reviews.review}</p>
            </div>
          </div>
          `
        ).join('')}
    </div>
  </div>
  <div class="input-review-container">
  <h2 class="input-review-title">Review this restaurant</h2>
    <input id="input-name" value="" aria-label="Text name here..." type="text" placeholder="Enter your Name...">
    <textarea id="input-review" value="" aria-label="Text review here..." type="text" placeholder="This Resto is awesome..."></textarea>
    <button id="input-submit" aria-label="submit">Submit Review</button>
  </div>
`

const createLikeButton = () => `
  <button aria-label="Like restaurant" id="like-button" class="like-button">
    <i class="fa fa-heart-o" aria-hidden="true"></i>
  </button>
`

const createUnlikeButton = () => `
  <button aria-label="unlike restaurant" id="like-Button" class="like-button">
    <i class="fa fa-heart" aria-hidden="true"></i>
  </button>
`

export {
  createRestaurantList,
  createRestaurantDetail,
  createLikeButton,
  createUnlikeButton
}