Javascript Bookmarker Functionality

Javascript Bookmarker Functionality
0

#1

Hi, I’m trying to make a bookmaker, I can’t figure out why the functionality isn’t working. I can’t get the page to save, give validation alerts, or delete what I input into the website name and url boxes. Sorry for posting a whole chunk of code, but any help is really appreciated! Thank you!


#2

Would you mind posting the html and css (optional)? Is all the JS? It seems like it is missing some parts. A link to a Codepen or JSFiddle of the project would make it easier for us to help you.


#3

I hope that works better!


#4

Your code was very unorganized, so I first put all the functions to the top of the script section. You probably have a bunch of [Object] [Object] bookmarks that you can not get rid of, because your code was attempting to add bookmarks even without submitting the form.

Below is my refactor of your code. Since you were using JQuery with your Bootstrap, I hope you don’t mind that I changed your some of your vanilla JS DOM manipulation to use JQuery syntax. I was able to remove half of your existing code which was either not correct logic or was unused.

To create a clean slate to start with in your local storage (get rid of all the [Object] [Object] items), you will need to uncomment a line near the bottom and run the script one time. This will get rid of all the bookmarks, so you can start from scratch. Also, you will need to comment that line back out or it will keep clearing out the local storage every time you load the page for the first time in each session.

NOTE: Your Visit button will not work unless you enter an http:// or https:// prefix for the URL. My suggestion is to force the user to enter the prefix with your Regex check

// Save Bookmark
function saveBookmark(e) {
  e.preventDefault();   // Prevent form from submitting
  // Get form values
  var siteName = $("#siteName").val();
  var siteURL = $("#siteURL").val();
  console.log(siteName,siteURL);
  if (validateForm(siteName, siteURL)) {
    var bookmark = { name: siteName, url: siteURL };
    var bookmarks = JSON.parse(localStorage.getItem("bookmarks"));
    if (bookmarks === null) {
      bookmarks = [];
    }    
    bookmarks.push(bookmark);                                     
    localStorage.setItem("bookmarks", JSON.stringify(bookmarks));   // Re-set back to localStorage
    document.getElementById('myForm').reset(); // clear form
    fetchBookmarks();    // Re-fetch bookmarks
  }
}

// Validate Form
function validateForm(siteName, siteURL) {
  if (!siteName || !siteURL) {
    alert("Please fill in the form");
    return false;
  }
  var expression = /[[email protected]:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[[email protected]:%_\+.~#?&//=]*)?/gi;
  var regex = new RegExp(expression);
  if (!siteURL.match(regex)) {
    alert("Please use a valid URL");
    return false;
  }
  return true;
}

// Delete bookmark function
function deleteBookmark(obj) {
  // Get bookmarks from localStorage
  var url = obj.getAttribute("href");
  var bookmarks = JSON.parse(localStorage.getItem("bookmarks"));
  // Loop through bookmarks
  for (var i = 0; i < bookmarks.length; i++) {
    if (bookmarks[i].url == url) {
      console.log('deleted bookmark')
      bookmarks.splice(i, 1);       // Remove from array
    }
  }
  localStorage.setItem("bookmarks", JSON.stringify(bookmarks));    // Re-set localStorage
  fetchBookmarks();   // Re-fetch bookmarks
  return false;
}

// Fetch bookmarks
function fetchBookmarks() {
  var bookmarks = JSON.parse(localStorage.getItem("bookmarks"));   // Get bookmarks from localStorage
  $("bookmarksResults").html("");
  if (bookmarks) {
    var bookmarksHTML = '';
    for (var i = 0; i < bookmarks.length; i++) {
      var name = bookmarks[i].name;
      var url = bookmarks[i].url;
      bookmarksHTML += '<div class="well">' + '<h3>' + name +
        '<a class="btn btn-default" target="_blank" href="' + url + '">Visit</a> ' +
        '<a onclick="return deleteBookmark(this);" class="btn btn-danger"  href="' + url + '">Delete</a>' +
        '</h3>' + '</div>';
    }
    $("#bookmarksResults").html(bookmarksHTML);
  }
}

$(function() { // run code below after page loads
  // uncomment the line below if you need to clear all of localStorage
  // localStorage.clear(); 
  
  // Listen for form submit
  $("#myForm").on("submit", saveBookmark);
  fetchBookmarks(); 
});

I had never used local storage before, so I learned something new today. Hope this helps you out.


#5

Here are a couple more refinements you can make to the code I posted above, which reduce and simplify the code further.

  1. In the deleteBookmark function, replace
  // Loop through bookmarks
  for (var i = 0; i < bookmarks.length; i++) {
    if (bookmarks[i].url == url) {
      console.log('deleted bookmark')
      bookmarks.splice(i, 1);       // Remove from array
    }
  }

with

  bookmarks.splice(bookmarks.indexOf(url),1); // removes bookmark using index
  1. In the saveBookmark function, replace
    var bookmarks = JSON.parse(localStorage.getItem("bookmarks"));
    if (bookmarks === null) {
      bookmarks = [];
    }  

with

    var bookmarks = JSON.parse(localStorage.getItem("bookmarks")) || [];

#6

One final modification to the code is to replace the following code in the saveBookmark function

    var bookmark = { name: siteName, url: siteURL };
    var bookmarks = JSON.parse(localStorage.getItem("bookmarks"));
    if (bookmarks === null) {
      bookmarks = [];
    }    
    bookmarks.push(bookmark);                                     
    localStorage.setItem("bookmarks", JSON.stringify(bookmarks));   // Re-set back to localStorage
    

with a call to a new function insertBookmark

    insertBookmark(siteName, siteURL);

Then all you need to do is add the following function called insertBookmark to your code. Note, that instead of just adding the bookmark to the end of the array, this function actually figures out where to insert the new bookmark into the bookmarks array, so it retains a sort order based on the Site Name.

NOTE: Since it does not sort during the fetch, you will have to clear the local storage before adding any new items, for it to show the correct sorted order. Alternatively, you could have sorted inside the fetchBookmarks function, but then there would be a sort anytime a book mark is deleted, added, or when the page loads in general. This way, it is only when bookmarks are added.

// inserts new bookmark in correct array location to keep bookmarks sorted by siteName
function insertBookmark(siteName, siteURL) {
    var bookmark = { name: siteName, url: siteURL };
    var bookmarks = JSON.parse(localStorage.getItem("bookmarks")) || [];  
    var index = bookmarks.findIndex(function(obj) {
      return siteName < obj.name ; // gets lowest index to
    });    
    bookmarks.splice((index < 0 ? 0 : index), 0, bookmark); // insert bookmark at correct index to maintain sorted array   
    localStorage.setItem("bookmarks", JSON.stringify(bookmarks));   // Re-set back to localStorage
}

Because I have made so many refinements to the original code I posted, here is a final version with all the changes made in the past couple of posts:

// Save Bookmark
function saveBookmark(e) {
  e.preventDefault();   // Prevent form from submitting
  // Get form values
  var siteName = $("#siteName").val();
  var siteURL = $("#siteURL").val();
  if (validateForm(siteName, siteURL)) {
    insertBookmark(siteName, siteURL);
    document.getElementById('myForm').reset(); // clear form
    fetchBookmarks();    // Re-fetch bookmarks
  }
}

// inserts new bookmark in correct array location to keep bookmarks sorted by siteName
function insertBookmark(siteName, siteURL) {
    var bookmark = { name: siteName, url: siteURL };
    var bookmarks = JSON.parse(localStorage.getItem("bookmarks")) || [];  
    var index = bookmarks.findIndex(function(obj) {
      return siteName < obj.name ; // gets lowest index to
    });    
    bookmarks.splice((index < 0 ? 0 : index), 0, bookmark); // insert bookmark at correct index to maintain sorted array   
    localStorage.setItem("bookmarks", JSON.stringify(bookmarks));   // Re-set back to localStorage
}

// Validate Form
function validateForm(siteName, siteURL) {
  if (!siteName || !siteURL) {
    alert("Please fill in the form");
    return false;
  }
  var expression = /[[email protected]:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[[email protected]:%_\+.~#?&//=]*)?/gi;
  var regex = new RegExp(expression);
  if (!siteURL.match(regex)) {
    alert("Please use a valid URL");
    return false;
  }
  return true;
}

// Delete bookmark function
function deleteBookmark(obj) {
  // Get bookmarks from localStorage
  var url = obj.getAttribute("href");
  var bookmarks = JSON.parse(localStorage.getItem("bookmarks"));
  bookmarks.splice(bookmarks.indexOf(url),1); // removes bookmark using index
  localStorage.setItem("bookmarks", JSON.stringify(bookmarks));    // Re-set localStorage
  fetchBookmarks();   // Re-fetch bookmarks
  return false;
}

// Fetch bookmarks
function fetchBookmarks() {
  var bookmarks = JSON.parse(localStorage.getItem("bookmarks"));   // Get bookmarks from localStorage
  $("bookmarksResults").html("");
  if (bookmarks) {
    var bookmarksHTML = '';
    for (var i = 0; i < bookmarks.length; i++) {
      var name = bookmarks[i].name;
      var url = bookmarks[i].url;
      bookmarksHTML += '<div class="well">' + '<h3>' + name +
        '<a class="btn btn-default" target="_blank" href="' + url + '">Visit</a> ' +
        '<a onclick="return deleteBookmark(this);" class="btn btn-danger"  href="' + url + '">Delete</a>' +
        '</h3>' + '</div>';
    }
    $("#bookmarksResults").html(bookmarksHTML);
  }
}

$(function() { // run code below after page loads
  // localStorage.clear();   
  // Listen for form submit
  $("#myForm").on("submit", saveBookmark);
  fetchBookmarks(); 
});