0

I have a code for a localstorage favorite list. It's working fine for example if I click on Article 1 (id: 22) or Article 4 (id: 25) it is added to the favorite list. So far fine. But what I need and can't do alone is: after I add some article id to My Favorite id's (In local storage), then I need when I click on that favorited article id item , I need the page to scroll down to its content.

Javascript code:

//index db

const favoriteButtonAttr = 'data-add-to-favorite';
const isFavorite = 'data-is-favorite';
const listSelector = '[data-my-favorites]';

class FavoritesList {
  constructor () {
    this.storageName = 'favoritesList';
    this.list = this.initList();
  }
  
  initList () {
    if (window.localStorage.getItem(this.storageName)) { 
      // todo: repetitive parse?
      const list = JSON.parse(window.localStorage.getItem(this.storageName));
      updateHtmlList(list);
      return list;
    } else {   
      return [];
    }
  }
  
  initButton(button) {
    const id = parseInt(button.getAttribute(favoriteButtonAttr));
    
    button.addEventListener('click', (event) => {
      const button = event.target;
      !inArray(id, this.list) ? this.list.push(id) : removeFromArray(id, this.list);
      setState(id, this.list);
      this.updateList();
    })
    
    function setState (id, list) {
      return button.toggleAttribute(isFavorite, inArray(id, list));
    }
    
    setState(id, this.list);
    return button;
  }
  
  updateList() {
    setLocalStorage(this.storageName, this.list);
    updateHtmlList(this.list); 
  }
}

function updateHtmlList(list) {
  if(list.length > 0) {
    // lastest favorites on top & don't modify original list;
    const newList = list.slice(0).reverse();
    favoritesHTMLElement.innerHTML = '';
    listItems = document.createElement('ul');
    newList.forEach( item => {
      let htmlLi = document.createElement('li');
      htmlLi.innerHTML = item;
      favoritesHTMLElement.appendChild(htmlLi);
    });
  } else {
    favoritesHTMLElement.innerHTML = '';
  }
} 

function inArray(element, array) {
  return array.indexOf(element) != -1;
}

function removeFromArray(element, array) {
  array.splice(array.indexOf(element), 1); 
}

function setLocalStorage(key, value) {
  console.log(value)
  window.localStorage.setItem(key, JSON.stringify(value));
}

const buttons = document.querySelectorAll(`[${favoriteButtonAttr}]`);
const favoritesHTMLElement = document.querySelector(listSelector);
let favorites = new FavoritesList();  
buttons.forEach( button => favorites.initButton(button) );

Html code:

<article class="layout">
  <div class="shop">
    <h1>Our articles</h1>
    <p>Articles will be added to favorite list ordered by last added.</p>
    <ul>
      <li id="22">
        <span>Article 1 (id: 22)</span>
        <button class="shop-item__favorite-button" data-add-to-favorite="22" data-favorite-title="Meredith dress">
          <span class="sr-only"
                data-favorite="Add to my favorites"
                data-favorite-added="Remove from my favorites"></span>
        </button>
      </li>
      <li id="23">
        <span>Article 2 (id: 23)</span>
        <button class="shop-item__favorite-button" data-add-to-favorite="23" data-favorite-title="Meredith Skirt">
          <span class="sr-only"
                data-favorite="Add to my favorites"
                data-favorite-added="Remove from my favorites"></span>
        </button>
      </li>
      <li id="24">
        <span>Article 3 (id: 24)</span>
        <button class="shop-item__favorite-button" data-add-to-favorite="24" data-favorite-title="Josephine short">
          <span class="sr-only"
                data-favorite="Add to my favorites"
                data-favorite-added="Remove from my favorites"></span>
        </button>
      </li>
      <li id="25">
        <span>Article 4 (id: 25)</span>
        <button class="shop-item__favorite-button" data-add-to-favorite="25" data-favorite-title="Josephine shirt">
          <span class="sr-only"
                data-favorite="Add to my favorites"
                data-favorite-added="Remove from my favorites"></span>
        </button>
      </li>
    </ul>
  </div>

  <section class="favorites">
    <h2>My Favorite id's (In local storage)</h2>
    <ul class="favorites__list" data-my-favorites data-my-favorites-empty="No favorites yet"></ul>
  </section>
</article>
fansko97
  • 33
  • 3
  • You say that you need the page to scroll down to its content. But, what's content? I don't seen the content of any article – Victor Mar 24 '22 at 08:45
  • If add to favorite list Article 3 (id: 24), than when it's click in the favorite list , page need to scroll to id24 like: . But it should be automated in the javascript code – fansko97 Mar 24 '22 at 08:49

1 Answers1

0

You have almost done. Check this:

function updateHtmlList(list) {
  if(list.length > 0) {
    // lastest favorites on top & don't modify original list;
    const newList = list.slice(0).reverse();
    favoritesHTMLElement.innerHTML = '';
    listItems = document.createElement('ul');
    newList.forEach( item => {
      let htmlLi = document.createElement('li');

      htmlLi.innerHTML = '<a href="#'+item+'" class="go-to-link">'+item+'</a>';      

      favoritesHTMLElement.appendChild(htmlLi);
    });
  } else {
    favoritesHTMLElement.innerHTML = '';
  }
} 

Instead adding only a text with the article id, you can add an anchor link. Your articles already have an identifier, so you only need a lin to that identifiers (with the # to indicate that you navigate to that point of the page). I added also a class go-to-link that you can use to give style to the link. But it's not mandatory.

UPDATE

Well, this change need a function to do the scroll. We can use this https://stackoverflow.com/a/43698126/18452174 with some changes because that function don't work when you do scroll from botton to top:

function scrollTo(animate, to, duration, extraOffset) {
  // When should we finish?
  var finishAt = Date.now() + duration;
  
  // Start
  requestAnimationFrame(tick);

  function tick() {
    // How many frames left? (60fps = 16.6ms per frame)
    var framesLeft = (finishAt - Date.now()) / 16.6;


  // How far do we have to go?
  var distance = to.getBoundingClientRect().top + (extraOffset || 0);
  if (distance == 0) {
    // Done (this shouldn't happen, belt & braces)
    return;
  }

  // Adjust by one frame's worth
  if (framesLeft <= 1) {
    // Last call
    animate.scrollTop += distance;
  } else {
    // Not the last, adjust and schedule next
    var dir = distance < 0 ? -1 : 1;
    animate.scrollTop += dir * Math.max(1, dir * distance / framesLeft);
    requestAnimationFrame(tick);
   }
  }
 }

I recomended you the use of jQuery (if you can, of course) because the previous function is a single animate call and jQuery manage cross browser. Your code become smaller and is a powerfull library.

Now, we need to change the foreach of updateHtmlList function:

  let htmlLi = document.createElement('li');
  
  let htmlA = document.createElement('a');
  htmlA.setAttribute('href', '#' + item);
  htmlA.setAttribute('class', 'go-to-link');
  htmlA.innerText = item;
  htmlA.addEventListener('click', function (e) {
    e.preventDefault();

     var link = document.getElementById(item)
     scrollTo(document.documentElement, link, 300, -100);
  });
  
  htmlLi.appendChild(htmlA);

  favoritesHTMLElement.appendChild(htmlLi);

Instead using a string for the link, we create the "a" element because we want to addEventListener. In the click event, we abort (preventDefault) the default action (scroll to anchor) and do the scroll with the animated function. You can change the time (300 milliseconds in the example) and also, we can add some offset here if we want. You said previously -100px, so you can add -100 to the destination scroll position.

Here https://jsfiddle.net/mn3zx4j0/1/ you have a version of the previous code with an extra to highlight the article. After add -100px, the scroll don't stop exactly in the article an maybe a bit confuse. So add an extra parameter (a callback function) to the scroll animation and when the scroll finish, the function is executed.

function highlightScrolled(item) {
  var color = item.style.backgroundColor;
    item.style.backgroundColor='#ffff00';

  setTimeout(function() {
    item.style.backgroundColor=color;
  }, 3000);
}

This function highligh the article with a yellow back color during 3 seconds. You can change other style if you prefer (bold, color, underline...)

Victor
  • 2,313
  • 2
  • 5
  • 13
  • Its working perfect Sir – fansko97 Mar 24 '22 at 10:04
  • I did accept the answer Sir. Can you make some offset so it scroll -100px of the top of the id? – fansko97 Mar 25 '22 at 08:10
  • The simple way maybe add some margin-top to the anchor link. If the margin-top is not an option for you, that I think is your case using the li, you can try to create an hidden element with the anchor like commented here https://stackoverflow.com/a/13184714/18452174. This hidden element is moved some offset to top, giving the position for the anchor link. So remove the id in your li tags and add an hidden link inside the li with the id – Victor Mar 25 '22 at 08:32
  • I manage to set the offset Sir thank you. Last thing I'd like to ask if it is possible in the localfavorite list to show not id number but data-favorite-title="Meredith Skirt" ? – fansko97 Mar 25 '22 at 08:57
  • I think I need more info about the problem because I can't see it. If you are writing the HTML, you can put "Meredith Skirt" instead of the id when you are creating the HTML. – Victor Mar 25 '22 at 10:59
  • Thank you Sir you point me to the right direction. I must say you are one of the best. Great support. Can the scroll in the javascript be more smooth instead of jump? I try in html scroll-behavior: smooth but not working on mobile. Can you touch something in the javascript code to make the scroll smooth? – fansko97 Mar 26 '22 at 09:00
  • I'm glad to help you. Check this https://stackoverflow.com/a/7717572/18452174 – Victor Mar 26 '22 at 09:10
  • I try it but can't implement it correctly to my javascript code. Can you add smooth scroll to that code correctly? – fansko97 Mar 26 '22 at 11:33