首页 > 解决方案 > 更新 CRUD 前端时收到 Javascript 程序的未定义错误

问题描述

我为我的 ruby​​ on rails 后端创建了一个前端 javascript,当我尝试更新书名时收到以下错误:

错误:app.js:65 未捕获类型错误:无法读取 App.handleEditClick 处未定义的属性“renderUpdateForm”(app.js:65)

我从后端 api 接收书名及其作者。

这是代码:

    document.addEventListener('DOMContentLoaded', () => {
  const app = new App();
  app.attachEventListeners();
  app.adapter.fetchAuthors().then(app.createAuthors);
  app.adapter.fetchBooks().then(app.createBooks);

});
    class Book {
  constructor(data) {
    this.id = data.id;
    this.title = data.title;
    const author = Author.findById(data.author_id);
    this.author = author.name;
    Book.all.push(this);
  }

  update({ title }) {
    this.title = title;
  }


  renderListItem() {
    return `
    <li>
      <h3>${this.title} - ${this.author}
      <button data-id=${this.id}>update</button>
        <button data-id=${this.id}>delete</button>
      </h3>
    </li>`;
  }

  renderUpdateForm() {
    return `
    <form data-id='${this.id}'>
      <label>Title</label>
      <p>
        <input type="text" value="${this.title}" />
      </p>

      <button type='submit'>Save Book</button>
    </form>
  `;
  }

  static findById(id) {
    return this.all.find(book => book.id === id);
  }
}

Book.all = [];

    class App {
  constructor() {
    this.adapter = new Adapter();

    this.handleEditClick = this.handleEditClick.bind(this);
    this.handleEditClick = this.handleDeleteClick.bind(this);
    this.handleFormSubmit = this.handleFormSubmit.bind(this);
    this.createBooks = this.createBooks.bind(this);
    this.createAuthors = this.createAuthors.bind(this);
    this.addBooks = this.addBooks.bind(this);

  }

  attachEventListeners() {
    $('#books-list').on('click', 'button', this.handleEditClick);
    $('#books-list').on('click', 'button', this.handleDeleteClick);
    $('#update').on('submit', 'form', this.handleFormSubmit);
  }

  createBooks(books) {
    books.forEach(book => {
      new Book(book);
    });
    console.log(this);
    this.addBooks();
  }

  createAuthors(authors) {
    authors.forEach(author => {
      new Author(author);
    });
    console.log(this);
    this.addAuthors();
  }

  addBooks() {
    $('#books-list').empty();
    Book.all.forEach(book => $('#books-list').append(book.renderListItem()));
  }

  addAuthors() {
    $('#authors-list').empty();
    Author.all.forEach(author => $('#authors-list').append(author.renderListItem()));
  }


  handleFormSubmit(e) {
    e.preventDefault();
    const id = e.target.dataset.id;
    const book = Book.findById(id);
    const title = $(e.target)
      .find('input')
      .val();

    const bodyJSON = { title };
    this.adapter.updateBook(book.id, bodyJSON).then(updatedBook => {
      const book = Book.findById(updatedBook.id);
      book.update(updatedBook);
      this.addBooks();
    });
  }

  handleEditClick(e) {
    const id = e.target.dataset.id;
    const book = Book.findById(id);
    $('#update').html(book.renderUpdateForm());
  }

  handleDeleteClick(e) {
    const id = e.target.dataset.id;
    const book = Book.findById(id);
    const title = $(e.target)
      .find('input')
      .val();

    const bodyJSON = { title };
    this.adapter.deleteBook(book.id, bodyJSON);

  }


}


 class Adapter {
  constructor() {
    this.baseUrl = 'http://localhost:3000/api/v1';
    this.headers = {
      'Content-Type': 'application/json',
      Accept: 'application/json'
    };
  }

  fetchBooks() {
    return this.get(`${this.baseUrl}/books`);
  }

  fetchAuthors() {
    return this.get(`${this.baseUrl}/authors`);
  }

  updateBook(id, body) {
    return this.patch(`${this.baseUrl}/books/${id}`, body);
  }

  deleteBook(id, body) {
    return this.delete(`${this.baseUrl}/books/${id}`, body);
  }

  get(url) {
    return fetch(url).then(res => res.json());
  }

  patch(url, body) {
    return fetch(url, {
      method: 'PATCH',
      headers: this.headers,
      body: JSON.stringify(body)
    }).then(res => res.json());
  }

  delete(url, body) {
    return fetch(url, {
      method: 'DELETE',
      headers: this.headers,
      body: JSON.stringify(body)
    }).then(res => res.json());
  }
}

标签: javascripthtmlapi

解决方案


const book = Book.findById(id);

返回undefined

这意味着没有那个条目ide.target.dataset.id可能具有与预期不同的值(console.log是您的朋友)。


为了防止这种类型的错误(因此当您使用 invalid/non-existent 时您的应用程序不会中断id),您可以将下一行包装在一个条件中:

handleEditClick(e) {
  const id = e.target.dataset.id;
  const book = Book.findById(id);
  if (book) {
     $('#update').html(book.renderUpdateForm());
  }
}

更好的检查是结果是否有一个名为 的函数renderUpdateForm

if (book && typeof book.renderUpdateForm === 'function') { 
  $('#update').html(book.renderUpdateForm())
}

或者如果它是 Book 实例:

if (book instanceof Book) { 
  $('#update').html(book.renderUpdateForm())
}

推荐阅读