skip to Main Content

I am doing a coding course on codecademy and am currently stuck at a certain question within a coding challenge. I have received 3 JS files, two of which I should not modify in any way, as I was told that they are helper functions I should use and a file with an array of books. Question 2 is leaving me completely baffled. I have sat on it for a solid 2 hours now and although it works locally on vscode it gives me the same error message over and over. I would greatly appreciate any help because I am really frustrated. I will first send the introduction of the challenge and the first question for some added content:

Intro:
In the code editor, we have provided you with the starting code for a Book Finder website. Once the application is complete, you will be able to input a genre, title, or author into the search bar, and get back a list of books that match that criteria. You can see the list of books that your application will search in bookList.js.

Your task is to finish building the application by completing the function definitions for the captureSearchValue(), filterBooks(), structureBooksAsHtml(), and searchBtnClickHandler() functions. You should only make edits to these four function definitions within script.js. We’ve defined helper functions in helper.js that you will need to use as you build out your program.

Question 1:
The captureSearchValue function captures the search bar input value and returns it.

My code for the first question is correct according to them.

Question 2:
The filterBooks() function takes in a search string and a list of books as parameters and returns all of the books that contain an exact match of the search input as an array of objects. Objects in this array should be formatted as books with title, author, and tags properties, similar to the original books array. It should use the flattenObjectValuesIntoArray() function to search all fields within a book object easily.

The helper code:

// Flatten object keys into an array so that we search the entire object by the input value
const flattenObjectValuesIntoArray = (arrOfObjs) => {
  let flattenedObj;
  const flattenedObjsArr = [];
  for (let obj = 0; obj < arrOfObjs.length; obj++) {
    const objValues = Object.values(arrOfObjs[obj]);
    flattenedObj = [...objValues.flat()]
    flattenedObjsArr.push(flattenedObj)
  }
  return flattenedObjsArr;
};

// Structure filtered books as HTML and return
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 = "";

  bookListContainer.append(...elements);
};

The array file:

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"]
  }
]

The index.html:

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="styles.css">
    <script src="bookList.js"></script>
    <script src="bookList.test.js"></script>
    <script src="helper.js"></script>
    <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>

my code:

// Click handler for search button
let cap = document.getElementById('search-bar')
let capValue = cap.value;
const captureSearchValue = () => {
return cap.value
};

const filterBooks = () => {
  let flattenedArr =flattenObjectValuesIntoArray(books);
  let match = [];
  for (let i = 0; i < flattenedArr.length; i++) {
    for (let j = 0; j < flattenedArr[i].length; j++) {
      if (flattenedArr[i][j] === capValue){
        match.push(books[i])
      }
    }
  }; return match
  };

// 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 = () => {};

// 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 = () => {};

// Grab search button from the DOM

// Attach an event listener to the search button
searchBtn.addEventListener("click", () => {
  searchBtnClickHandler(books);
});

I am only at the filterBooks function, I have not reached the other functions yet so dont mind them.

This is the message i am getting for question 2 when i submit my answer:

Given the filter fantasy, your filterBooks function returned an array with 0 elements. We expected it to return 2.

I would greatly appreciate any help on this problem. It does not seem to make any sense to me

I think that the issue is related to the capvalue but I am honestly clueless

2

Answers


  1. You have created the variable outside the function that is being set when the DOM is loaded once so when the DOM is loaded the search-bar input value is ''. That is why when you are looping, you are checking that the string of book is equal to '' every time. This is causing the issue.

    There is a simple fix for this, just use the function captureSearchValue to create the capValue variable inside the fiterBooks function, then it will run perfectly fine

    This is how your code should look like

    const searchBtn = document.querySelector('#search-btn');
    
    // Click handler for search button
    let cap = document.getElementById('search-bar')
    // Remove the capValue variable
    const captureSearchValue = () => {
        return cap.value
    };
    
    const filterBooks = () => {
        let flattenedArr = flattenObjectValuesIntoArray(books);
        // Add the capValue variable here
        let capValue = captureSearchValue();
        let match = [];
        for (let i = 0; i < flattenedArr.length; i++) {
            for (let j = 0; j < flattenedArr[i].length; j++) {
                if (flattenedArr[i][j] === capValue) {
                    match.push(books[i])
                }
            }
        };
        return match
    };
    

    If this doesn’t work, you can also try changing the condition to:

    if (flattenedArr[i][j].includes(capValue)) {
        match.push(books[i])
    }
    

    The previous condition was checking if the book string value is 100% equal to the search value that might also be causing the problem for example 'fantasy' !== ' fantasy ' even a space can trigger this to be false. The new condition just checks if the string is included or not. This might also fix the issue.

    Login or Signup to reply.
  2. You should really learn how:

    1. Filter works, this is cleary handy for this situatie
    2. Map works, also handy
    3. Find works, this is the same as filter but limits itself to 1 result

    You can replace all these function with an forEach but learning these will improve your code a lot 🙂

    This could be the result:

    ///////////////////
    // DATA
    //////////////////
    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"]
      }
    ]
    
    ///////////////////
    // HELPERS
    //////////////////
    function flattenObjectValuesIntoArray (arrOfObjs) {
      let flattenedObj;
      const flattenedObjsArr = [];
      for (let obj = 0; obj < arrOfObjs.length; obj++) {
        const objValues = Object.values(arrOfObjs[obj]);
        flattenedObj = [...objValues.flat()]
        flattenedObjsArr.push(flattenedObj)
      }
      return flattenedObjsArr;
    };
    
    ///////////////////
    // TASK
    //////////////////
    
    /*
    The filterBooks() function takes in a search string and a list of books as parameters and returns all of the books that contain an exact match of the search input as an array of objects.
    */
    
    function filterBooks(search, books) {
      // Flatten books array
      flattenedBooks = flattenObjectValuesIntoArray(books);
    
      // Now we can filter for an EXACT match
      let results = flattenedBooks.filter(bookProps => 
        bookProps.filter((prop) => prop === search).length
     )
     
     // We still got to remap like the books array, but if we assume titles are unique, we can still use the original books array to find the correct objects.
     let mappedResults = results.map(book => books.find((b) => b.title === book[0]))
     
      
     return mappedResults
    }
    
    
    // EXAMPLE
    console.log(filterBooks('fiction', books));

    Last but not least, about

    'fantasy' !== ' fantasy '
    

    This is easily fixed by using the trim() function 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search