Build a Bookmark Manager App - Build a Bookmark Manager App

Tell us what’s happening:

I am not sure why step 5 is failing because I did check if “name”, “category”, and “url” exists in the hasBookmarks variable by an every() method and saved the result into hasKeys variable. However, this alone wasn’t working so I thought the values needed to be valid as well, so I added hasValues variable to check if the values are a string. I am not sure what I am doing wrong and where. Can anyone please tell me what I am doing wrong and how to fix it? Any help is appreciated.

Your code so far

/* file: script.js */

function getBookmarks(){
  const hasBookmarks = JSON.parse(localStorage.getItem("bookmarks"));
  if(hasBookmarks === null || !Array.isArray(hasBookmarks)){
    return [];
  }
  const hasKeys = hasBookmarks.every((obj) => "name" in obj && "category" in obj && "url" in obj);

  const hasValues =  hasBookmarks.every((obj) => typeof(obj.name) === typeof("str") && obj.name !== "" && typeof(obj.category) === typeof("str") && obj.category !== "" && typeof(obj.url) === typeof("str") && obj.url !== "");

  if(!hasKeys || !hasValues){
    return [];
  }

  return hasBookmarks;
}


<!-- file: index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=0.0">
    <title>Bookmark Manager</title>
    <link rel="stylesheet" href="styles.css">
</head>

<body>
    <main>
        <section id="main-section">
            <h1>Bookmark Manager</h1>
            <div id="dropdown">
                <label for="category-dropdown">Select a category:</label>
                <select id="category-dropdown" name="options">
                    <option value="news" selected>News</option>
                    <option value="entertainment">Entertainment</option>
                    <option value="work">Work</option>
                    <option value="miscellaneous">Miscellaneous</option>
                </select>
            </div>
            <div id="buttons">
                <button type="button" id="view-category-button">View Category</button>
                <button type="button" id="add-bookmark-button">Add Bookmark</button>
            </div>
        </section>

        <section id="form-section" class="hidden">
            <form>
                <h2 class="category-name"></h2>
                <div>
                    <label for="name">Name:</label>
                    <input type="text" id="name">
                </div>
                <div>
                    <label for="url">URL:</label>
                    <input type="text" id="url">
                </div>
                <div>
                    <button type="button" id="close-form-button">Go Back</button>
                    <button type="button" id="add-bookmark-button-form">Add Bookmark</button>
                </div>
            </form>
        </section>

        <section id="bookmark-list-section" class="hidden">
            <h2 class="category-name"></h2>
            <div id="category-list">
            </div>
            <div>
                <button type="button" id="close-list-button">Go Back</button>
                <button type="button" id="delete-bookmark-button">Delete Bookmark</button>
            </div>
        </section>

    </main>
    <script src="script.js"></script>
</body>

</html>

/* file: styles.css */


:root {
  --light-grey: #f5f6f7;
  --dark-grey: #0a0a23;
  --yellow: #f1be32;
  --golden-yellow: #feac32;
}

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

main {
  display: flex;
  justify-content: center;
}

body {
  background-color: var(--dark-grey);
}

.hidden {
  display: none;
}

section {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

select,
input,
label {
  margin-left: 10px;
}

div {
  padding: 30px;
  display: flex;
  justify-content: center;
}

.close-form-button {
  background: none;
  border: none;
  cursor: pointer;
}

h1, h2 {
  margin-top: 20px;
  text-align: center;
}

#category-list {
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  background-color: var(--light-grey);
  align-self: center;
  width: 80%;
  margin-top: 15px;
  border-radius: 10px;
}

#category-list,
h1,
h2,
label {
  color: var(--light-grey);
}

#category-list p {
  color: var(--dark-grey);
}

button {
  cursor: pointer;
  padding: 5px;
  width: 100px;
  margin: 10px;
  color: var(--dark-grey);
  background-color: var(--golden-yellow);
  background-image: linear-gradient(#fecc4c, #ffac33);
  border-color: var(--golden-yellow);
  border-width: 3px;
}

button:hover {
  background-image: linear-gradient(#ffcc4c, #f89808);
}

section {
  margin-top: 60px;
  border: 2px solid var(--golden-yellow);
  width: fit-content;
  border-radius: 10px;
}

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Safari/605.1.15

Challenge Information:

Build a Bookmark Manager App - Build a Bookmark Manager App

GitHub Link: freeCodeCamp/curriculum/challenges/english/blocks/lab-bookmark-manager-app/66def5467aee701733aaf8cc.md at main · freeCodeCamp/freeCodeCamp · GitHub

what happens if there is a corrupted value that is not valid JSON in local storage?

It will throw a syntax error. So try and catch block. It worked. Thanks for all your help!

Hi again. I am stuck on step 11 on the Tests: case section. For step 11, I created an event listener to #add-bookmark-button-form and inside of the event listener I saved the call to the getBookmarks() function to bookmarksArrObj and pushed appropriately all the .value and then stored it in localStorage. For some reason it doesn’t work. Any help is appreciated. Thank you.

The code is below:

function getBookmarks(){

const bookmarks = localStorage.getItem(“bookmarks”);

if(!bookmarks){

return [];

}

try{

const hasBookmarks = JSON.parse(localStorage.getItem(“bookmarks”));

const hasKeys = hasBookmarks.every((obj) => “name” in obj && “category” in obj && “url” in obj);

if(Array.isArray(hasBookmarks) && hasKeys){

return hasBookmarks;

}

else{

return [];

}

}

catch{

return [];

}

}

const mainSection = document.getElementById(“main-section”);

const formSection = document.getElementById(“form-section”);

function displayOrCloseForm(){

mainSection.classList.toggle(“hidden”);

formSection.classList.toggle(“hidden”);

}

const addBookmarkBtn = document.getElementById(“add-bookmark-button”);

const categoryName = document.querySelector(“.category-name”);

const dropdownMenu = document.getElementById(“category-dropdown”);

addBookmarkBtn.addEventListener(“click”, () => {

categoryName.textContent = dropdownMenu.value;

displayOrCloseForm();

});

const closeFormBtn = document.getElementById(“close-form-button”);

closeFormBtn.addEventListener(“click”, displayOrCloseForm);

const addFormBookmarkBtn = document.getElementById(“add-bookmark-button-form”);

const name = document.getElementById(“name”);

const url = document.getElementById(“url”);

// Below is the isssue

addFormBookmarkBtn.addEventListener(“click”, () => {

const bookmarksArrObj = getBookmarks();

bookmarksArrObj.push({name: name.value, category: dropdownMenu.value, url: url.value});

localStorage.setItem(“bookmarks”, JSON.stringify(bookmarksArrObj));

});

Please repost your code formatting it properly so that it is readable

When you enter a code block into a forum post, please precede it with three backticks to make it easier to read.

You can also use the “preformatted text” tool in the editor (</>) to add the backticks.

See this post to find the backtick on your keyboard.
Note: Backticks (`) are not single quotes (').

Tell us what’s happening:

I am stuck on step 11 on the Tests: case section. For step 11, I created an event listener to #add-bookmark-button-form and inside of the event listener I saved the call to the getBookmarks() function to bookmarksArrObj and pushed appropriately all the .value and then stored it in localStorage. For some reason it doesn’t work. Any help is appreciated. Thank you.

Note: I created another post instead of replaying to the existing post because I could not format the code appropriately.

Your code so far

/* file: script.js */

function getBookmarks(){
  const bookmarks = localStorage.getItem("bookmarks");
  if(!bookmarks){
    return [];
  }

  try{
    const hasBookmarks = JSON.parse(localStorage.getItem("bookmarks"));
    const hasKeys = hasBookmarks.every((obj) => "name" in obj && "category" in obj && "url" in obj);

    if(Array.isArray(hasBookmarks) && hasKeys){
      return hasBookmarks;
    }
    else{
      return [];
    }
  }
  catch{
    return [];
  }
}

const mainSection = document.getElementById("main-section");
const formSection = document.getElementById("form-section");

function displayOrCloseForm(){
  mainSection.classList.toggle("hidden");
  formSection.classList.toggle("hidden");
}

const addBookmarkBtn = document.getElementById("add-bookmark-button");
const categoryName = document.querySelector(".category-name");
const dropdownMenu = document.getElementById("category-dropdown");

addBookmarkBtn.addEventListener("click", () => {
  categoryName.textContent = dropdownMenu.value;
  displayOrCloseForm();
});

const closeFormBtn = document.getElementById("close-form-button");

closeFormBtn.addEventListener("click", displayOrCloseForm);

const addFormBookmarkBtn = document.getElementById("add-bookmark-button-form");
const name = document.getElementById("name");
const url = document.getElementById("url");

// Below is the issue
addFormBookmarkBtn.addEventListener("click", (e) => {
  // Note: I tried without preventDefault() but it wasn't still working
  e.preventDefault();
  const bookmarksArrObj = getBookmarks();
  bookmarksArrObj.push({name: name.value, category: dropdownMenu.value, url: url.value});

  localStorage.setItem("bookmarks", JSON.stringify(bookmarksArrObj));
});





<!-- file: index.html -->

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=0.0">
    <title>Bookmark Manager</title>
    <link rel="stylesheet" href="styles.css">
</head>

<body>
    <main>
        <section id="main-section">
            <h1>Bookmark Manager</h1>
            <div id="dropdown">
                <label for="category-dropdown">Select a category:</label>
                <select id="category-dropdown" name="options">
                    <option value="news" selected>News</option>
                    <option value="entertainment">Entertainment</option>
                    <option value="work">Work</option>
                    <option value="miscellaneous">Miscellaneous</option>
                </select>
            </div>
            <div id="buttons">
                <button type="button" id="view-category-button">View Category</button>
                <button type="button" id="add-bookmark-button">Add Bookmark</button>
            </div>
        </section>

        <section id="form-section" class="hidden">
            <form>
                <h2 class="category-name"></h2>
                <div>
                    <label for="name">Name:</label>
                    <input type="text" id="name">
                </div>
                <div>
                    <label for="url">URL:</label>
                    <input type="text" id="url">
                </div>
                <div>
                    <button type="button" id="close-form-button">Go Back</button>
                    <button type="button" id="add-bookmark-button-form">Add Bookmark</button>
                </div>
            </form>
        </section>

        <section id="bookmark-list-section" class="hidden">
            <h2 class="category-name"></h2>
            <div id="category-list">
            </div>
            <div>
                <button type="button" id="close-list-button">Go Back</button>
                <button type="button" id="delete-bookmark-button">Delete Bookmark</button>
            </div>
        </section>

    </main>
    <script src="script.js"></script>
</body>

</html>

/* file: styles.css */

:root {
  --light-grey: #f5f6f7;
  --dark-grey: #0a0a23;
  --yellow: #f1be32;
  --golden-yellow: #feac32;
}

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

main {
  display: flex;
  justify-content: center;
}

body {
  background-color: var(--dark-grey);
}

.hidden {
  display: none;
}

section {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

select,
input,
label {
  margin-left: 10px;
}

div {
  padding: 30px;
  display: flex;
  justify-content: center;
}

.close-form-button {
  background: none;
  border: none;
  cursor: pointer;
}

h1, h2 {
  margin-top: 20px;
  text-align: center;
}

#category-list {
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  background-color: var(--light-grey);
  align-self: center;
  width: 80%;
  margin-top: 15px;
  border-radius: 10px;
}

#category-list,
h1,
h2,
label {
  color: var(--light-grey);
}

#category-list p {
  color: var(--dark-grey);
}

button {
  cursor: pointer;
  padding: 5px;
  width: 100px;
  margin: 10px;
  color: var(--dark-grey);
  background-color: var(--golden-yellow);
  background-image: linear-gradient(#fecc4c, #ffac33);
  border-color: var(--golden-yellow);
  border-width: 3px;
}

button:hover {
  background-image: linear-gradient(#ffcc4c, #f89808);
}

section {
  margin-top: 60px;
  border: 2px solid var(--golden-yellow);
  width: fit-content;
  border-radius: 10px;
}

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Safari/605.1.15

Challenge Information:

Build a Bookmark Manager App - Build a Bookmark Manager App

GitHub Link: freeCodeCamp/curriculum/challenges/english/blocks/lab-bookmark-manager-app/66def5467aee701733aaf8cc.md at main · freeCodeCamp/freeCodeCamp · GitHub

Please let us know what was not clear in the post that shows you how to format your code so we can take steps to make it more understandable.

I went ahead and combined your posts for you. In the future, please reply to the original thread to add further updates.

Did you implement User Story #7?

Thank you for your help. I was able to get it working. Also, the post said to click on </> then use Backticks to start a code section, but when I use it, it doesn’t work. I tried single and double quotes but it wasn’t working. Unless I am not supposed to see the results until I have replayed to the post? Apologize for the inconvenience.

I’m glad you got it working!

Would you tell us if this wording makes the “how to format your code” post easier to understand?


There are two ways you can format your code to make it easier to read and test:

  1. After you copy/paste your code into the editor, select it by dragging your mouse over it then click the (</>) button in the toolbar to automatically wrap your code in backticks. (You can click on the animated demo image below to enlarge it.)

  2. Manually add three backticks on a new line above your code and on a new line after your code. Note that a backtick is NOT the same as a single quote('). To find the backtick key on your keyboard, see this post.

To see changes to your post as you make them, you can click the (M+) button on the toolbar to bring up the rich text editor:


Thank you.

Yes, this wording is much clear. I was able to follow the instruction and put my code in the reply section.

Now I am stuck on step 17 on the Tests: case section or step 10 on the User Stories: section. For step 10, I added an event listener to #view-category-button button and inside of it I used a forEach() method to loop through bookmarksArrObj variable, which contains the array of object from localStorage, and if no category is found then it will display No Bookmarks Found. For some reason the test keeps failing. Thank you.

function getBookmarks(){
  const bookmarks = localStorage.getItem("bookmarks");
  if(!bookmarks){
    return [];
  }

  try{
    // You must use try/catch block because JSON.parse() can get a syntax error if
    // the string isn't formatted into as vaild JSON
    // Note: bookmarks varible above has nothing to do with the key bookmarks below
    const hasBookmarks = JSON.parse(localStorage.getItem("bookmarks"));
    // In every() method, [] is consider true
    const hasKeys = hasBookmarks.every((obj) => "name" in obj && "category" in obj && "url" in obj);

    if(Array.isArray(hasBookmarks) && hasKeys){
      return hasBookmarks;
    }
    else{
      return [];
    }
  }
  catch{
    return [];
  }
}

const mainSection = document.getElementById("main-section");
const formSection = document.getElementById("form-section");

function displayOrCloseForm(){
  mainSection.classList.toggle("hidden");
  formSection.classList.toggle("hidden");
}

const addBookmarkBtn = document.getElementById("add-bookmark-button");
const categoryName = document.querySelectorAll(".category-name");
const dropdownMenu = document.getElementById("category-dropdown");

addBookmarkBtn.addEventListener("click", () => {
  categoryName.forEach((element) => element.textContent = dropdownMenu.value[0].toUpperCase() + dropdownMenu.value.slice(1));
  displayOrCloseForm();
});

const closeFormBtn = document.getElementById("close-form-button");

closeFormBtn.addEventListener("click", displayOrCloseForm);

const addFormBookmarkBtn = document.getElementById("add-bookmark-button-form");
const nameOfCategory = document.getElementById("name");
const url = document.getElementById("url");


addFormBookmarkBtn.addEventListener("click", (e) => {
  const bookmarksArrObj = getBookmarks();
  bookmarksArrObj.push({name: nameOfCategory.value, category: dropdownMenu.value, url: url.value});

  localStorage.setItem("bookmarks", JSON.stringify(bookmarksArrObj));

  nameOfCategory.value = "";
  url.value = "";
  displayOrCloseForm();
});

const displayBookmarks = document.getElementById("bookmark-list-section");

function displayOrHideCategory(){
  mainSection.classList.toggle("hidden");
  displayBookmarks.classList.toggle("hidden");
}

const viewCategory = document.getElementById("view-category-button");
const listOfCategory = document.getElementById("category-list");

// Below is the issue
viewCategory.addEventListener("click", () => categoryName.forEach((element) => {element.textContent = dropdownMenu.value[0].toUpperCase() + dropdownMenu.value.slice(1);

  const bookmarksArrObj = getBookmarks();
  let hasCategory = false;
  listOfCategory.innerHTML = "";

  bookmarksArrObj.forEach((obj) => {
    if(obj.category === dropdownMenu.value){
      listOfCategory.innerHTML += `<input id="${obj.name}" value="${obj.name}" name="bookmark" type="radio"/>`;
      hasCategory = true;
    }
  });

  if(hasCategory === false){
    listOfCategory.innerHTML = "<p>No Bookmarks Found</p>";
  }
}));

Thanks for letting us know about the “how to format your code” wording.

I couldn’t even click the submit button because the syntax of your event listener is broken.

Also, why are you looping through all of the categories. Isn’t the objective to view the bookmarks for just the category that is selected?

I got it working. Thanks for you help!