为Ruby on Rails后端开发的JS前端更新书名时出现Undefined错误
Hey Carla, let's break down why you're hitting this Cannot read property 'renderUpdateForm' of undefined error and fix it step by step!
What's Causing the Error?
The core issues are a mix of botched event binding, unbuttoned button events, and type mismatch when looking up your Book instance:
1. You Overwrote Your handleEditClick Binding
In your App constructor, you accidentally replaced the bound handleEditClick with handleDeleteClick:
constructor() { this.adapter = new Adapter(); this.handleEditClick = this.handleEditClick.bind(this); this.handleEditClick = this.handleDeleteClick.bind(this); // Oops! Overwrote the first binding // ... rest of your code }
This meant when you clicked the "update" button, it was trying to run delete logic instead of edit logic.
2. All Buttons Trigger Both Edit and Delete Events
You attached both handleEditClick and handleDeleteClick to every <button> in the books list. No matter which button you clicked, both functions fired—creating chaos.
3. ID Type Mismatch Breaks findById
Your Book.id is a number (from your Rails API), but e.target.dataset.id returns a string. When you use === in findById, the type mismatch means it can't find the Book instance, returning undefined—hence the error when trying to call renderUpdateForm() on it.
Step-by-Step Fixes
1. Fix Event Binding in the App Constructor
Correct the binding so each handler gets its own bound version:
constructor() { this.adapter = new Adapter(); this.handleEditClick = this.handleEditClick.bind(this); this.handleDeleteClick = this.handleDeleteClick.bind(this); // Bind delete handler separately this.handleFormSubmit = this.handleFormSubmit.bind(this); this.createBooks = this.createBooks.bind(this); this.createAuthors = this.createAuthors.bind(this); this.addBooks = this.addBooks.bind(this); }
2. Distinguish Update/Delete Buttons
Add classes to your buttons so you can target them separately in your listener:
// In Book.renderListItem() renderListItem() { return ` <li> <h3>${this.title} - ${this.author} <button data-id=${this.id} class="update-btn">update</button> <button data-id=${this.id} class="delete-btn">delete</button> </h3> </li>`; }
Then update your event listeners to target specific buttons:
// In App.attachEventListeners() attachEventListeners() { $('#books-list').on('click', '.update-btn', this.handleEditClick); $('#books-list').on('click', '.delete-btn', this.handleDeleteClick); $('#update').on('submit', 'form', this.handleFormSubmit); }
3. Fix ID Type Mismatch
Convert the string ID to a number when looking up your Book instance. You can do this either in findById:
// In Book.findById() static findById(id) { return this.all.find(book => book.id === parseInt(id)); }
Or directly in your handleEditClick and handleDeleteClick methods:
handleEditClick(e) { const id = parseInt(e.target.dataset.id); const book = Book.findById(id); $('#update').html(book.renderUpdateForm()); }
Bonus: Clean Up Delete Logic
Your delete function was sending unnecessary body data. Simplify it:
// In App.handleDeleteClick() handleDeleteClick(e) { const id = parseInt(e.target.dataset.id); const book = Book.findById(id); this.adapter.deleteBook(book.id) .then(() => { // Remove the book from your array and refresh the list Book.all = Book.all.filter(b => b.id !== book.id); this.addBooks(); }); } // In Adapter.deleteBook() deleteBook(id) { return this.delete(`${this.baseUrl}/books/${id}`); } delete(url) { return fetch(url, { method: 'DELETE', headers: this.headers }).then(res => res.json()); }
After making these changes, your update form should render correctly when you click the "update" button, and the error should be gone!
内容的提问来源于stack exchange,提问作者Carla Holcomb

