Book Finder Project Help - Can't get it to work - Please help

Ive tried to test my code and can’t understand why I don’t get an array back after flattening it. So I don’t get anything returned at all. Can anyone help please?

<html>
  <head>
    <link rel="stylesheet" href="styles.css">
    <script src="script.js" defer></script>
  </head>
  <body>
    <h1>Book Finder</h1>
    <input id="search-bar" type="text" placeholder="Search for books by tags">
    <button class="btn" id="search-btn">Search</button>
    <div id="bookList">
      <!-- List of books will be rendered here -->
    </div>
  </body>
</html>
const captureSearchValue = () => {
  var searchValue = document.getElementById("search-bar").value;
  return searchValue;
};
const books = [
  {
    title: "The City We Became",
    author: "N. K. Jemisin",
    tags: ["fantasy", "fiction", "afrofutursim", "science fiction", "sci-fi"]
  },
  {
    title: "The Catcher in the Rye",
    author: "J. D. Salinger",
    tags: ["fiction", "young adult", "YA", "realism", "coming of age", "classic"]
  },
  {
    title: "The Hundred Thousand Kingdoms",
    author: "N. K. Jemisin",
    tags: ["fantasy", "fiction", "adventure", "series"]
  },
  {
    title: "Sapiens: A Brief History of Humankind",
    author: "Yuval Noah Harari",
    tags: ["nonfiction", "history", "anthropology", "science", "sociology"]
  },
  {
    title: "Behave: The Biology of Humans at Our Best and Worst",
    author: "Robert M. Sapolsky",
    tags: ["nonfiction", "anthropology", "science", "sociology", "biology"]
  },
  {
    title: "The Parable of the Talents",
    author: "Octavia Butler", 
    tags: ["fiction", "dystopian", "science fiction"]
  },
  {
    title: "1984",
    author: "George Orwell", 
    tags: ["fiction", "dystopian", "science fiction", "classics", "adult"]
  },
  {
    title: "Remarkably Bright Creatures",
    author: "Shelby Van Pelt",
    tags: ["fiction", "mystery", "magical realism"]
  },
  {
    title: "Crying in H Mart",
    author: "Michelle Zauner",
    tags: ["memoir", "nonfiction", "autobiography"]
  },
  {
    title: "Wild: From Lost to Found on the Pacific Crest Trail",
    author: "Cheryl Strayed",
    tags: ["nonfiction", "memoir", "adventure", "travel"]
  }
]



const filterBooks = () => {
  const searchValue = captureSearchValue();

  const filteredBooks = books.filter(book =>
    Object.values(book).flat().some(value =>
      value.toString().toLowerCase().includes(searchValue.toLowerCase())
    )
  );

  return filteredBooks;
};

const structureBookAsHtml = (book) => {
  const bookDiv = document.createElement("div");
  bookDiv.setAttribute('class', 'bookDiv');

  const bookTitle = document.createElement("h2");
  bookTitle.innerHTML = book.title;
  bookTitle.setAttribute('class', 'bookTitle');

  const bookAuthor = document.createElement("h3");
  bookAuthor.innerHTML = book.author;

  const bookTags = document.createElement("p");
  bookTags.innerHTML = book.tags.join(", ");

  bookDiv.append(bookTitle, bookAuthor, bookTags);

  return bookDiv;
};

const renderBooksToDom = (elements) => {
  const bookListContainer = document.querySelector("#bookList");
  bookListContainer.innerHTML = "";

  elements.forEach((book) => {
    const bookDiv = structureBookAsHtml(book);
    bookListContainer.appendChild(bookDiv);
  });
};

const searchBtnClickHandler = () => {
  const filteredBooks = filterBooks();
  renderBooksToDom(filteredBooks);
};

const searchBtn = document.getElementById("search-btn");
searchBtn.addEventListener("click", searchBtnClickHandler);

I’ve tried it in the workspace and it works, I can’t see the problem here

Array.prototype.flat(), while supported in the latest versions of all notable browsers, it may yet be unsupported in the LE.

1 Like

Thanks for checking it for me. That’s really strange as I can’t get any results rendered??

The next question is that if the array is in another js file, how do I use it in the script file? Can I just add it as a script in the html file?

Thanks for looking at my code. Maybe I should try without this.

1 Like

Yeah so about the flat function, it depends on the browser or the Node.js version, while for the array, yes you can just add the two file on the HTML and use it like if it’s only one js file. For example:

<!DOCTYPE html>
<head>

</head>
<body>
    <script src="script.js"></script>
    <script src="script2.js"></script>
</body>

script.js:

const myArray = [1, 2, 3, 4, 5];

script2.js:
console.log(myArray);

1 Like

it is a solution code

index.html

Book Finder

Search

Book Finder

Search

script.js

// Click handler for search button
const captureSearchValue = () => {
return document.getElementById(“search-bar”).value.toLowerCase();
};
// Filter books based on search input
const filterBooks = (searchValue, books) => {
const sanitizedSearchValue = searchValue.toLowerCase().replace(/\s+/g, ‘’); // Remove spaces from search input and convert to lowercase
const searchGenres = sanitizedSearchValue.split(‘,’); // Split search input into individual genres
return books.filter((book) => {
const sanitizedTitle = book.title.toLowerCase().replace(/\s+/g, ‘’); // Remove spaces from book title and convert to lowercase
const sanitizedAuthor = book.author.toLowerCase().replace(/\s+/g, ‘’); // Remove spaces from book author and convert to lowercase
const sanitizedTags = book.tags.map(tag => tag.toLowerCase().replace(/\s+/g, ‘’)); // Remove spaces from tags and convert to lowercase
const titleMatch = searchGenres.some(genre => sanitizedTitle.includes(genre));
const authorMatch = searchGenres.some(genre => sanitizedAuthor.includes(genre));
const tagsMatch = searchGenres.some(genre => sanitizedTags.includes(genre));
return titleMatch || authorMatch || tagsMatch;
});
};
// Empty the book list container, iterate over list of filtered books, return list of books formatted as HTML using the function in helper.js
const structureBooksAsHtml = (filteredBooks) => {
return filteredBooks.map(book => structureBookAsHtml(book));
};
// Handler triggered when a user clickers the “Search” button. Chains previously defined functions together to filter books based on the search value, formats the books as HTML and renders them to the DOM
const searchBtnClickHandler = () => {
const searchValue = captureSearchValue();
const filteredBooks = filterBooks(searchValue, books);
const formattedBooks = structureBooksAsHtml(filteredBooks);
renderBooksToDom(formattedBooks);
};

// Grab search button from the DOM
const searchBtn = document.getElementById(‘search-btn’);
// Attach an event listener to the search button
searchBtn.addEventListener(‘click’, searchBtnClickHandler);

3 Likes

hi mega4790273551, i tried run your code and it works. thanks for sharing your solution and put comment for everyline so that i can also learn why it been code that way, etc, etc. i dont know how many times i question my decision in this career path hshshshs

Thank you! This code works! I was stuck on the last one and this helped a lot.

Thank you. I was also stuck. Interestingly, I had a function that returned exactly the same list of books as your filterBooks function did but it wasn’t accepted. Quite frustrating!

This is my code for functions which worked just fine and helped me to pass all tests.

const captureSearchValue = () => {
    const searchBar = document.getElementById("search-bar");
    return searchBar.value;  
  };

const filterBooks = (searchString, bookList) => {
    const searchLower = searchString.toLowerCase();
    const filteredBooks = bookList.filter(book => {
      const titleMatch = book.title.toLowerCase() === searchLower;
      const authorMatch = book.author.toLowerCase() === searchLower;
      const tagsMatch = book.tags.some(tag => tag.toLowerCase() === searchLower);
      return titleMatch || authorMatch || tagsMatch;
  
    });
     
     return filteredBooks;
  };

const structureBooksAsHtml = (books) => {
    const bookElements = books.map(book => structureBookAsHtml(book));
    return bookElements;
  };

const searchBtnClickHandler = (books) => {
    // Capture the search value
    const searchInput = captureSearchValue();
    const filteredBooks = filterBooks(searchInput, books);
    const bookElements = structureBooksAsHtml(filteredBooks);
    renderBooksToDom(bookElements);
  };

  // Grab search button from the DOM
  const searchBtn = document.getElementById('search-btn');
  
  // Attach an event listener to the search button
  searchBtn.addEventListener("click", () => { searchBtnClickHandler(books) });