0

Is there any way to store toggled/activated item using localstorage and reload it? I'm building a habit tracker and want the selected stars stay active when reloading the page.

So I tried localstorage.setItem with queryselectorAll, but it's not working. Also tried stringify but only empty array was saved to localstorage.

let today = new Date();
let currentMonth = today.getMonth();
let currentYear = today.getFullYear();
const trackerBody = document.querySelector(".js-tracker-body");

function showTracker(month, year) {
  const selectedDate = new Date(year, month);
  const lastDate = new Date(
    selectedDate.getFullYear(),
    selectedDate.getMonth() + 1,
    0
  );

  let date = 1;
  for (let i = 0; i < 6; i++) {
    const row = document.createElement("tr");

    for (let j = 0; j < 6; j++) {
      if (date <= lastDate.getDate()) {
        const cell = document.createElement("td");
        const cellPtag = document.createElement("p");
        const cellText = document.createTextNode(date);
        const cellIcon = document.createElement("i");
        cell.setAttribute("class", "habit-count");
        cellIcon.setAttribute("class", "fas fa-star star-icon");
        cellPtag.appendChild(cellText);
        cell.appendChild(cellPtag);
        cell.appendChild(cellIcon);
        row.appendChild(cell);
        date++;
      } else {
        break;
      }
    }
    trackerBody.appendChild(row);
  }
}

showTracker(currentMonth, currentYear);

document.body.addEventListener("click", e => {
  if (e.target.closest(".fa-star")) {
    e.target.classList.toggle('selected');
  }
  saveSelectedTracker();
});

function saveSelectedTracker() {
  const selectedTracker = document.querySelectorAll('.selected');
  localStorage.setItem('selected', selectedTracker);
}
.tracker {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #fff;
  background-color: #413f63;
}

.tracker-head {
  margin-bottom: 30px;
  text-align: center;
}

.date-picker {
  margin-bottom: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.previous,
.next {
  padding: 0 20px;
  font-size: 17px;
}

.monthAndYear {
  font-size: 36px;
  font-weight: 300;
}

.habit-content {
  font-size: 16px;
  font-weight: 300;
}

.tracker-items {
  font-size: 20px;
  text-align: center;
}

tr {
  display: flex;
}

.habit-count {
  padding: 0 10px 15px 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.habit-count:last-child {
  padding-right: 0;
}

.habit-count p {
  margin-bottom: 5px;
  font-size: 14px;
}

.star-icon {
  font-size: 30px;
  color: #c2b7b0;
}

.selected {
  color: #f4df21;
}
<div class="wrapper">
      <div class="tracker">
        <div class="tracker-head">
          <div class="date-picker">
            <a class="previous" onclick="previous()">
              <i class="fas fa-chevron-left"></i>
            </a>
            <strong class="monthAndYear"></strong>
            <a class="next" onclick="next()">
              <i class="fas fa-chevron-right"></i>
            </a>
          </div>
          <h1 class="js-habit-content habit-content"></h1>
        </div>
        <div class="tracker-main">
          <table class="traker-items">
            <thead></thead>
            <tbody class="js-tracker-body"></tbody>
          </table>
        </div>
      </div>
    </div>
        <script
      src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.1/js/all.min.js"
      integrity="sha256-HkXXtFRaflZ7gjmpjGQBENGnq8NIno4SDNq/3DbkMgo="
      crossorigin="anonymous"
    ></script>
function showTracker(month, year) {
  const selectedDate = new Date(year, month);
  const lastDate = new Date(
    selectedDate.getFullYear(),
    selectedDate.getMonth() + 1,
    0
  );

  monthAndYear.innerHTML = `${months[month]} ${year}`;
  trackerBody.innerHTML = "";

  let date = 1;
  for (let i = 0; i < 6; i++) {
    const row = document.createElement("tr");

    for (let j = 0; j < 6; j++) {
      if (date <= lastDate.getDate()) {
        const cell = document.createElement("td");
        const cellPtag = document.createElement("p");
        const cellText = document.createTextNode(date);
        const cellIcon = document.createElement("i");
        cell.setAttribute("class", "habit-count");
        cellIcon.setAttribute("class", "fas fa-star star-icon");
        cellPtag.appendChild(cellText);
        cell.appendChild(cellPtag);
        cell.appendChild(cellIcon);
        row.appendChild(cell);
        date++;
      } else {
        break;
      }
    }
    trackerBody.appendChild(row);
  }
}

showTracker(currentMonth, currentYear);

document.body.addEventListener("click", e => {
  if (e.target.closest(".fa-star")) {
    e.target.classList.toggle('selected');
  }
  saveSelectedTracker();
});

function saveSelectedTracker() {
  const selectedTracker = document.querySelectorAll('.selected');
  localStorage.setItem('selected', selectedTracker);
}
Ava Kim
  • 47
  • 1
  • 5
  • 1
    Does this answer your question? [Persist variables between page loads](https://stackoverflow.com/questions/29986657/persist-variables-between-page-loads) – Liam Jul 16 '20 at 13:42

3 Answers3

0

I think the issue is that you're saving references to the actual elements on the page, vs data about which items are selected. Try changing it so that you save an array of identifiers for which items are selected, and then on page load looked for that list and reapplied the selected class to those.

You can do a quick check that your .setItem is working by hardcoding a simple string vs the variable you're currently using.

0

Perhaps try setting the index (value of j) into the cellIcon, like this:

cellIcon.setAttribute("data-index", j);

then in saveSelectedTracker get all the selected cells as you are doing, but save the index of j instead.

const selectedTracker = document.querySelectorAll('.selected');
const starredIndexes = [];
selectedTracker.forEach(function(item) {
  starredIndexes.push(item.getAttribute('data-index'));
});
localStorage.setItem('selected', JSON.stringify(starredIndexes));

then in your showTracker method, pull out the array from local storage, deserialize and use the array to check if the star should be marked with the css class selected.

const starredIndexes = JSON.parse(localStorage.getItem('selected'))

//in your forloop
if(starredIndexes && Array.isArray(starredIndexes) && starredIndexes.indexOf(j) !== -1){
  cellIcon.setAttribute("class", "fas fa-star star-icon selected"); //mark ones saved in local storage
}else{
  cellIcon.setAttribute("class", "fas fa-star star-icon");
}

I think this would accomplish the gist of what you are trying to do. Let me know if you have any questions.

Rob Smitha
  • 395
  • 5
  • 8
0

You should not try to store the elements themselves in the localStorage; instead, store their indexes.

  const stars = document.querySelectorAll('.fa-star > path');
  let stored = localStorage.getItem("selected") || '[]'
  let indexes = JSON.parse(stored)
  for(const index of indexes){
    stars[index].classList.add('selected');
  }

  document.body.addEventListener("click", e => {
    if (e.target.closest(".fa-star")) {
      e.target.classList.toggle('selected');
    }
    saveSelectedTracker();
  });

  function saveSelectedTracker() {
    const indexes = [];
    for(let i = 0; i < stars.length; i++){
      if(stars[i].classList.contains("selected")){
        indexes.push(i);
      }
    }
    console.log(indexes);
    localStorage.setItem('selected', JSON.stringify(indexes));
  }

Working Demo

Unmitigated
  • 76,500
  • 11
  • 62
  • 80