West Midlands | 25-ITP-Sep | Ali Naru | Sprint 2 | feature/BookLibrary#334
West Midlands | 25-ITP-Sep | Ali Naru | Sprint 2 | feature/BookLibrary#334MohammedNaru wants to merge 6 commits intoCodeYourFuture:mainfrom
Conversation
… storage handling
|
Your PR's title isn't in the expected format. Please check the expected title format, and update yours to match. Reason: Wrong number of parts separated by |s If this PR is not coursework, please add the NotCoursework label (and message on Slack in #cyf-curriculum or it will probably not be noticed). If this PR needs reviewed, please add the 'Needs Review' label to this PR after you have resolved the issues listed above. |
|
Your PR couldn't be matched to an assignment in this module. Please check its title is in the correct format, and that you only have one PR per assignment. If this PR is not coursework, please add the NotCoursework label (and message on Slack in #cyf-curriculum or it will probably not be noticed). If this PR needs reviewed, please add the 'Needs Review' label to this PR after you have resolved the issues listed above. |
2 similar comments
|
Your PR couldn't be matched to an assignment in this module. Please check its title is in the correct format, and that you only have one PR per assignment. If this PR is not coursework, please add the NotCoursework label (and message on Slack in #cyf-curriculum or it will probably not be noticed). If this PR needs reviewed, please add the 'Needs Review' label to this PR after you have resolved the issues listed above. |
|
Your PR couldn't be matched to an assignment in this module. Please check its title is in the correct format, and that you only have one PR per assignment. If this PR is not coursework, please add the NotCoursework label (and message on Slack in #cyf-curriculum or it will probably not be noticed). If this PR needs reviewed, please add the 'Needs Review' label to this PR after you have resolved the issues listed above. |
cjyuan
left a comment
There was a problem hiding this comment.
-
There are some
console.log()statements left in your code. If they are not needed for the app to function, you should remove them to make the code clean. -
Can you check if any of this general feedback can help you further improve your code?
https://github.com/cjyuan/Module-Data-Flows/blob/book-library-feedback/debugging/book-library/feedback.md
Doing so can help me speed up the review process. Thanks.
…nd input validation
I have now reviewed and refactored these changes, please review. |
There was a problem hiding this comment.
Pull request overview
This PR refactors and debugs a book library application, fixing several critical bugs and improving code quality. The changes modernize the JavaScript code with better practices while maintaining functionality.
Key changes:
- Fixed bugs including incorrect variable references (e.g.,
title.valueinstead ofauthor.value), missing parentheses in loops, and typo in event listener names - Refactored the render function to use modern DOM manipulation with
forEachand event delegation patterns - Added input validation with trimming and proper type conversion, plus form clearing after submission
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.
| File | Description |
|---|---|
| debugging/book-library/script.js | Fixed multiple bugs, refactored render logic with modern JavaScript patterns, improved variable naming, and added input validation and form clearing |
| debugging/book-library/index.html | Added semantic HTML attributes (lang, title), corrected input types from custom to standard text/number, changed script loading to module type, and improved code formatting |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| class="form-control" | ||
| id="pages" | ||
| name="pages" | ||
| required |
There was a problem hiding this comment.
The HTML input type is number, but the JavaScript parses it with parseInt(). While this works, it's redundant since number inputs already return numeric strings. The HTML5 number input also doesn't prevent negative values by default. Consider adding a min="1" attribute to the pages input in the HTML to enforce positive values at the form level.
| required | |
| required | |
| min="1" |
| if (!title || !author || isNaN(pages)) { | ||
| alert("Please fill all fields correctly!"); |
There was a problem hiding this comment.
The validation doesn't check for negative page numbers or zero pages. Consider adding validation: if (!title || !author || isNaN(pages) || pages <= 0) to ensure meaningful book data is stored.
| if (!title || !author || isNaN(pages)) { | |
| alert("Please fill all fields correctly!"); | |
| if (!title || !author || isNaN(pages) || pages <= 0) { | |
| alert("Please fill all fields correctly! Page number must be a positive integer."); |
| myLibrary.splice(i, 1); | ||
| document.querySelectorAll(".delete-book").forEach(button => { | ||
| button.addEventListener("click", (e) => { | ||
| const index = e.target.dataset.index; |
There was a problem hiding this comment.
[nitpick] The dataset.index property returns a string. While JavaScript will coerce this string to a number when used with splice(), it's better to be explicit about type conversions. Consider: const index = parseInt(e.target.dataset.index, 10);
| <th>Author</th> | ||
| <th>Number of Pages</th> | ||
| <th>Read</th> | ||
| <th></th> |
There was a problem hiding this comment.
The last table header is empty (<th></th>), which is poor for accessibility. Screen readers won't announce what this column represents. Consider adding appropriate text like "Actions" or visually hiding it with <th><span class="sr-only">Actions</span></th> using Bootstrap's sr-only class.
| <th></th> | |
| <th><span class="sr-only">Actions</span></th> |
| // Add event listeners for buttons | ||
| document.querySelectorAll(".toggle-read").forEach(button => { | ||
| button.addEventListener("click", (e) => { | ||
| const index = e.target.dataset.index; |
There was a problem hiding this comment.
[nitpick] The dataset.index property returns a string. While JavaScript will coerce this string to a number when used with array indexing, it's better to be explicit about type conversions. Consider: const index = parseInt(e.target.dataset.index, 10);
| document.querySelectorAll(".toggle-read").forEach(button => { | ||
| button.addEventListener("click", (e) => { | ||
| const index = e.target.dataset.index; | ||
| myLibrary[index].check = !myLibrary[index].check; | ||
| render(); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Event listeners are being re-added every time render() is called, which can cause performance issues and unexpected behavior. Since the table is completely regenerated each time (line 64 clears innerHTML), the old event listeners are removed with the DOM elements, but this approach is inefficient.
Consider using event delegation by attaching a single event listener to the table or tbody instead:
tbody.addEventListener("click", (e) => {
if (e.target.classList.contains("toggle-read")) {
const index = parseInt(e.target.dataset.index, 10);
myLibrary[index].check = !myLibrary[index].check;
render();
}
});| // Display a non-blocking notification | ||
| const notification = document.createElement("div"); | ||
| notification.textContent = "Book deleted successfully."; | ||
| notification.className = "notification"; | ||
| document.body.appendChild(notification); | ||
|
|
||
| // Remove the notification after 3 seconds | ||
| setTimeout(() => { | ||
| notification.remove(); | ||
| }, 3000); |
There was a problem hiding this comment.
The notification element is created and added after calling render(), which means if render() throws an error, the user won't see the notification. Additionally, multiple rapid deletions will create multiple notification elements that aren't cleaned up properly. Consider moving the notification display before render() or implementing a notification queue system to handle multiple notifications gracefully.
cjyuan
left a comment
There was a problem hiding this comment.
It's a good idea to get a second opinion at the code from AI.
I am sure there is a way to use it outside the scope of a PR so that the AI messages won't interfere with the review.
There was a problem hiding this comment.
There are errors in the HTML code. Please fix them.
| const notification = document.createElement("div"); | ||
| notification.textContent = "Book deleted successfully."; | ||
| notification.className = "notification"; | ||
| document.body.appendChild(notification); | ||
|
|
There was a problem hiding this comment.
This approach is better than using alert() for showing notification.
Please note that when the notification is added to the bottom of the page, there is a chance that the user won't see the message when there are too many books on the list. (Change is optional as this is not part of the original implementation)
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| type="button" | ||
| value="Submit" | ||
| class="btn btn-primary" | ||
| onclick="submit();" |
There was a problem hiding this comment.
Using inline event handlers like onclick="submit();" is considered a bad practice and violates Content Security Policy (CSP) best practices. Consider moving this to an event listener in the JavaScript file: document.querySelector('input[type="button"]').addEventListener('click', submit);
| onclick="submit();" |
| @@ -50,54 +49,67 @@ function Book(title, author, pages, check) { | |||
| this.check = check; | |||
There was a problem hiding this comment.
The property name check in the Book constructor is ambiguous. It should be renamed to something more descriptive like isRead or hasBeenRead to clearly indicate what it represents. This would make the code more self-documenting.
| <meta | ||
| charset="utf-8" | ||
| name="viewport" | ||
| content="width=device-width, initial-scale=1.0" | ||
| /> | ||
| /> |
There was a problem hiding this comment.
The meta tag has invalid HTML structure. The charset and viewport attributes cannot be combined in a single meta tag. They should be split into two separate tags:
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />| const titleInput = document.getElementById("title"); | ||
| const authorInput = document.getElementById("author"); | ||
| const pagesInput = document.getElementById("pages"); | ||
| const readCheckbox = document.getElementById("check"); |
There was a problem hiding this comment.
The script is loaded with type="module", which creates a module scope. However, the window.submit = submit; assignment at the end of script.js won't work reliably because the DOM elements (titleInput, authorInput, etc.) are queried at the top level before the DOM is fully loaded. These queries happen immediately when the script loads, but the elements don't exist yet. Move the DOM element queries inside the submit() function or into a DOMContentLoaded event handler.
| // Add event listeners for buttons | ||
| document.querySelectorAll(".toggle-read").forEach(button => { | ||
| button.addEventListener("click", (e) => { | ||
| const index = e.target.dataset.index; |
There was a problem hiding this comment.
The dataset.index returns a string, not a number. When using myLibrary[index] with a string index on an array, it still works due to JavaScript's type coercion, but it's better practice to convert it to a number explicitly: const index = parseInt(e.target.dataset.index, 10);. This ensures proper array indexing and prevents potential bugs if the array is later used in contexts where type matters.
| document.querySelectorAll(".delete-book").forEach(button => { | ||
| button.addEventListener("click", (e) => { | ||
| const index = e.target.dataset.index; | ||
| myLibrary.splice(index, 1); | ||
| render(); | ||
|
|
||
| // Display a non-blocking notification | ||
| const notification = document.createElement("div"); | ||
| notification.textContent = "Book deleted successfully."; | ||
| notification.className = "notification"; | ||
| document.body.appendChild(notification); | ||
|
|
||
| // Remove the notification after 3 seconds | ||
| setTimeout(() => { | ||
| notification.remove(); | ||
| }, 3000); | ||
| }); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Every time render() is called, new event listeners are attached to all delete buttons. This creates memory leaks as old listeners aren't removed. Use event delegation instead by attaching a single listener to the table element.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Hi CJ I have refactored changes, I did not meant to intentionally add copilot as a reviewer, I don't have access to remove it, please can you remove it as a reviewer with Admin access, thanks |
|
According the W3C validator, your HTML code still have errors. |
…input validation, and styling
|
@copilot open a new pull request to apply changes based on the comments in this thread
I have updated now, I had rebase errors so I had to restart my changes but all should be working now, please review |
|
Changes looks great! Well done! |
Book Library Pull Request
Self checklist
Changelist
Refactored code to include debugging and pass requirements.
Questions
No questions for reviewer.