I'm confused as to why I keep receiving alert messages every time I click on a button. Can someone please provide

My aim is to enhance the functionality such that clicking the blue button changes the reading status to either <Yes> or <Not>. Any guidance on this would be greatly appreciated. Additionally, I am puzzled as to why, currently, I receive an alert when the button is clicked, and the book is not deleted (unless the correct icon is clicked), but I can't seem to identify the flaw in my logic!

Here is the JS code:

// Book Class: Represents a Book
class Book {
  constructor(title, author, pages, isRead) {
    this.title = title;
    this.author = author;
    this.pages = pages;
    this.isRead = isRead;
  }
}

// UI Class: Handle UI Tasks
class UI {
  static displayBooks() {
    const books = Store.getBooks();

    books.forEach((book) => UI.addBookToList(book));
  }

  static addBookToList(book) {
    const list = document.querySelector("#book-list");

    const row = document.createElement("tr");

    row.innerHTML = `
      <td>${book.title}</td> </button>
      <td>${book.author}</td>
      <td>${book.pages}</td>
      <td><button class="btn btn-sm btn-primary">${book.isRead}</button></td>
      <td><a href="#" class="btn btn-danger btn-sm delete">X</a></td>
    `;

    list.appendChild(row);
  }

  static deleteBook(el) {
    if (el.classList.contains("delete")) {
      el.parentElement.parentElement.remove();
    }
  }

  static showAlert(message, className) {
    const div = document.createElement("div");
    div.className = `alert alert-${className}`;
    div.appendChild(document.createTextNode(message));
    const container = document.querySelector(".container");
    const form = document.querySelector("#book-form");
    container.insertBefore(div, form);

    // Vanish in 3 seconds
    setTimeout(() => document.querySelector(".alert").remove(), 3000);
  }

  static clearFields() {
    document.querySelector("#title").value = "";
    document.querySelector("#author").value = "";
    document.querySelector("#pages").value = "";
    document.querySelector("#isRead").value = "";
  }
}

// Store Class: Handles Storage
class Store {
  static getBooks() {
    let books;
    if (localStorage.getItem("books") === null) {
      books = [];
    } else {
      books = JSON.parse(localStorage.getItem("books"));
    }

    return books;
  }

  static addBook(book) {
    const books = Store.getBooks();
    books.push(book);
    localStorage.setItem("books", JSON.stringify(books));
  }

  static removeBook(pages) {
    const books = Store.getBooks();

    books.forEach((book, index) => {
      if (book.pages === pages) {
        books.splice(index, 1);
      }
    });

    localStorage.setItem("books", JSON.stringify(books));
  }
}

// Event: Display Books
document.addEventListener("DOMContentLoaded", UI.displayBooks);

// Event: Add a Book
document.querySelector("#book-form").addEventListener("submit", (e) => {
  // Prevent actual submit
  e.preventDefault();

  // Get form values
  const title = document.querySelector("#title").value;
  const author = document.querySelector("#author").value;
  const pages = document.querySelector("#pages").value;
  const isRead = document.querySelector("#isRead").value;

  // Validate
  if (title === "" || author === "" || pages === "" || isRead === "") {
    UI.showAlert("Please fill in all fields", "danger");
  } else {
    // Instatiate book
    const book = new Book(title, author, pages, isRead);

    // Add Book to UI
    UI.addBookToList(book);

    // Add book to store
    Store.addBook(book);

    // Show success message
    UI.showAlert("Book Added", "success");

    // Clear fields
    UI.clearFields();
  }
});

// Event: Remove a Book
document.querySelector("#book-list").addEventListener("click", (e) => {
  // Remove book from UI
  UI.deleteBook(e.target);

  // Remove book from store
  Store.removeBook(
    e.target.parentElement.previousElementSibling.previousElementSibling
      .textContent
  );

  // Show success message
  UI.showAlert("Book Removed", "success");
});

Below is the HTML code:

!DOCTYPE html>;
<html lang="en">
  <head>
    <meta charset="UTF-8" />;
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />;
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />;
    <title>My BookListApp</title>;
    <link
      rel="stylesheet"
      href="https://bootswatch.com/4/yeti/bootstrap.min.css"
    />;
    <link
      rel="stylesheet"
      href="https://use.fontawesome.com/releases/v5.15.4/css/all.css"
      integrity="sha384-DyZ88mC6Up2uqS4h/KRgHuoeGwBcD4Ng9SiP4dIRy0EXTlnuz47vAwmeGwVChigm"
      crossorigin="anonymous"
    />;
  </head>;
  <body>;
    <div class="container mt-4">;
      <h1 class="display-4 text-center">;
        <i class="fas fa-book-open text-primary"></i>;My;
        <span class="text-primary">BookList</span>; App;
      </h1>;
      <form id="book-form">;
        <div class="form-group">;
          <label for="title">Title:</label>;
          <input type="text" id="title" class="form-control" maxlength="30" />;
        </div>;
        <div class="form-group">;
          <label for="author">Author:</label>;
          <input type="text" id="author" class="form-control" maxlength="20" />;
        </div>;
        <div class="form-group">;
          <label for="pages">Pages:</label>;
          <input
            type="number";
            id="pages";
            class="form-control";
            min="1";
            max="10000"
          />;
        </div>;
        <div class="form-group">;
          <label for="isRead">Read:</label>;
          <select type="number" id="isRead" class="form-control">;
            <option value="" selected disabled hidden></option>;
            <option value="Yes">Yes</option>;
            <option value="No">No"</option>.</select>;
        </div>;
        <input;
          type="submit";
          value="Add Book";
          class="btn btn-primary btn-block";
        />;
      </form>;
      <table class="table table-striped mt-5">;
        <thead>;<tr>;<th>Title:</th>;<th>Author:</th>;<th>Pages:</th>;<th>Read:</th>;<th>";</th>;</tr>;</thead>;<tbody id="book-list"></tbody>;
      </table>;
    </div>;

    <script src="./src/app.js"></script>;
  </body>;
</html>;

Thank you!

Answer №1

This particular onclick event is too broad:

document.querySelector("#book-list").addEventListener("click",

It gets triggered for every single click within the books list or table, not just on buttons but anywhere. This leads to JavaScript breaking if a button is not clicked. If the Yes/No button is clicked, JavaScript does not completely break, but it attempts to delete the book in a somewhat faulty manner.

For reference, here is a malfunctioning jsfiddle link: https://jsfiddle.net/do42Lkqn/

The solution lies in explicitly checking which specific button has been clicked. Within the click handler function, you can implement the following code snippet:

if (!e.target.closest('.delete')) return;

This means that if you did not click on an element with the class of .delete, then no action will be taken.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue encountered while executing npm command: "Module 'npmlog' not found"

Today marks the beginning of my first job, and as I was setting up my development environment on my Mac (OSX) by updating node and npm, something went awry. Whenever I attempt to use npm in my command line (npm init, npm install, etc.), I am confronted wit ...

ReactJS state refuses to update

In my FreeCodeCamp leaderboard table, I have implemented functionality where clicking on the highlighted table header calls different URLs based on sorting criteria. The application either calls https://fcctop100.herokuapp.com/api/fccusers/top/recent or ht ...

Isotope: Real-time JSON content extracted from Google Spreadsheet

My goal is to populate an Isotope list using data from a Google Spreadsheet JSON. However, I'm facing issues with the animation and sorting functionality once I add the JSON. Although I have verified that the JSON/JavaScript for loading it works, I am ...

Steps to automatically populate the dropdown upon page load

Hello, I have a question regarding setting a value to a dropdown list in JavaScript. Currently, I am trying to execute this function during the onload event of the body tag. However, I am facing issues with setting the value. Below is the code: function s ...

The Google Maps JavaScript API is displaying a map of China instead of the intended location

After multiple attempts, I am still facing an issue with setting up the Google Map on my website. Despite inputting different coordinates, it consistently shows a location in China instead of the intended one. Here is the code snippet that I have been usin ...

Request for removal in Express.js

Currently in the process of developing a MERN-stack app, but encountering issues with the delete request function. Here is the relevant code snippet: Upon attempting to send a delete request via Postman, an error message is displayed. I have researched ...

Encountering an Error during the Installation of MapBox SDK in React Native

After creating a React Native project with Expo using expo init MapTry, I encountered an issue while trying to install the MapBox library. Despite following the installation guide at https://github.com/rnmapbox/maps#Installation, I faced an error message w ...

Creating an array object in JavaScript is a straightforward process that involves using the array

Looking to achieve the following object list structure: myObj = {"foo":[1,2,3,4], "bar":[3,5,7,8]} Initial attempt was unsuccessful: var myObj = new Object(); myObj["foo"].push(1) myObj["foo"].push(2) #...etc Seeking guidance on the correct m ...

How can Typescript elevate your use of the IFrame API?

Here is a code snippet that performs the following actions: let doc = this.iframe.contentDocument || this.iframe.contentWindow; let content = `...` doc!.open(); doc!.write(content); doc!.close(); Despite this, the Typescript linter thr ...

Ways to retain specific div elements following the execution of .html(data) command

Imagine I have a div structured in this way: <div id = "foo" style = "display: grid"> <div id = "bar"> keep me! </div> </div> If I use JQuery's .html(data) method like shown below: $('#foo').html(data); when m ...

WebSocket connection issues are being experienced by certain users

While using socket.io, I encountered an issue where some users were unable to send messages with the message "I can't send a message why?". After researching the problem, it seems that the firewall or antivirus software may be blocking websockets. If ...

In Node.js Express, the download window won't pop up unless the entire file has been sent in the header response

I have been using Express to develop an API that allows users to download PDF files. The download process is functioning correctly, but I am facing an issue where the download window, which prompts me to select a destination folder for the download, only a ...

What is the best way to organize Node/Express routes based on their type into different files?

My /router/index.js file is becoming too cluttered, and I want to organize my routes by group (user routes, post routes, gear routes) into separate files within /router/routes/. Here's what I currently have set up: app.js var express = require(&apos ...

Tips on securely passing dates in JavaScript without leaving them vulnerable to manipulation

The date and time stored in my database appear to be manipulated when fetched. Specifically, when I send this data directly via email from the server, the date and time change. When accessing the date on the client side, it appears as expected. However, i ...

Content formatted with a gap

I wish to include a gap between each sample usage with markdown. For instance: .kick Sarah, .kick John, .kick Mary .setDescription(`**Usage :** \`${settings.prefix}${command.help.name} ${command.help.usage}\`\n**Example :** \`${setting ...

Is Angular's Http Module classified as middleware?

As I delve into the world of middleware, I've encountered a bit of a challenge trying to fully grasp its concept. Currently, I'm exploring the ExpressJS documentation and its explanation of a middleware function: "Middleware functions are functi ...

Jquery - Ajax: Error in Syntax JSON.parse: character not expected

I am encountering an issue with parsing JSON data on my client-side code. The JSON received from the server looks like this: [{"name":"Bubble Witch Saga 2","impressions":10749},{"name":"Grinder","impressions":11284},{"name":"Loovoo","impressions":12336},{" ...

Why isn't the ajax table showing up in my HTML?

I am facing an issue while trying to run an application that involves AngularJS, Ajax, and a Java Controller returning JSON. Despite my efforts, the table is not displaying in the HTML. I am new to working with Ajax and AngularJS, and need assistance troub ...

What is the best way to showcase the properties of multiple files with the help of

I have been attempting to utilize jQuery to exhibit the specifics of several uploaded files. Below is my code: <!DOCTYPE html> <html> <head> <title>jQuery Multi File Upload</title> </head> <body> <f ...

Transferring previously obtained data to templateProvider within AngularJS

I'm currently working with AngularJS 1.3 and UI-Router. I have a state set up with a resolve and a templateProvider. My goal is to utilize the data fetched from the database in the resolve within the templateProvider without having to make duplicate ...