2

I am working on a small project to get into Vue js. It is supposed to be a Habittracker. I currently have a bug, if you reload the page and add new habits, my function that is supposed to change the background does not work properly.

here it shows the bug and here is how my array looks:

0
: 
{id: 0, title: "1", ready: false}

1
: 
{id: 1, title: "123", ready: false}

2
: 
{id: 2, title: "123", ready: false}

3
: 
{id: 0, title: "123", ready: true}

I get why it is not working because I am using a counter to assign the id, which resets to 0 when reloaded.

<div class="q-pa-md" v-for="(habit, index) in habits" :key="habit.id">
    <q-card class="my-card" :id="habit.id" ref="card">
      <q-card-section>
        <q-checkbox
          id="checkbox"
          v-model="habit.ready"
          @click="changeToTransparent(habit)"
        >
        </q-checkbox>
        {{ habit.title }}

        <q-btn-dropdown flat class="more" icon="more_horiz">
          <q-list>
            <q-item clickable v-close-popup @click="deletehabit(index)">
              <q-item-section>
                <q-item-label>Delete</q-item-label>
              </q-item-section>
            </q-item>

            <q-item clickable v-close-popup @click="edithabitbutton(index)">
              <q-item-section>
                <q-item-label>Edit</q-item-label>
              </q-item-section>
            </q-item>
          </q-list>
        </q-btn-dropdown>
      </q-card-section>
    </q-card>
    <div>

let counter = 0;
const habits = ref([]);


const addHabit = () => {
  
  habits.value.push({ id: counter++, title: habittitle.value, ready: false });
  savetolocalstorage();
  habittitle.value = "";
};

const changeToTransparent = (habit) => {

  if(document.getElementById(habit.id) != null) {
    if (habit.ready) {
    document.getElementById(habit.id).style.backgroundColor =
      "rgba(170,193,200,0.25)";
    savetolocalstorage();
  } else {
    document.getElementById(habit.id).style.backgroundColor = "";
    savetolocalstorage();
  }
  }
 
}

Any ideas on how I could fix this?

4
  • I suggest you use vue-cookie Commented Dec 21, 2022 at 9:14
  • Give a try to that one: github.com/ai/nanoid Commented Dec 21, 2022 at 9:21
  • Share how habits look Commented Dec 21, 2022 at 9:24
  • Otherwise, this can be helpful regarding the persistency: stackoverflow.com/a/66872372/8816585 Commented Dec 21, 2022 at 9:47

2 Answers 2

3

You need to load your localStorage and set the length to the counter value. I made a working example here. I also improved your code so that it's more in line with Vue's concepts. As @Rahul Purohit pointed out, you will need to JSON.stringify the result when saving and JSON.parse it when loading.

<template>
  <q-input label="Title" v-model="habitTitle" />
  <q-btn label="Add habit" @click="addHabit" />
  <div class="q-pa-md" v-for="(habit, index) in habits" :key="habit.id">
    <q-card
      class="my-card"
      :id="habit.id"
      :ref="(el) => (cardRefs[habit.id] = el)"
    >
      <q-card-section>
        <q-checkbox
          id="checkbox"
          v-model="habit.ready"
          @click="changeToTransparent(habit)"
        >
        </q-checkbox>
        {{ habit.id }} {{ habit.title }}

        <q-btn-dropdown flat class="more" icon="more_horiz">
          <q-list>
            <q-item clickable v-close-popup @click="deletehabit(index)">
              <q-item-section>
                <q-item-label>Delete</q-item-label>
              </q-item-section>
            </q-item>

            <q-item clickable v-close-popup @click="edithabitbutton(index)">
              <q-item-section>
                <q-item-label>Edit</q-item-label>
              </q-item-section>
            </q-item>
          </q-list>
        </q-btn-dropdown>
      </q-card-section>
    </q-card>
  </div>
</template>

<script setup>
const { ref, onMounted } = require("vue");

// it can be just a let.
const counter = ref(0);
const habits = ref([]);
const habitTitle = ref("test");
const cardRefs = ref({});

const saveToLocalStorage = () => console.log("saved");

const addHabit = () => {
  habits.value.push({
    id: counter.value++,
    title: habitTitle.value,
    ready: false,
  });
  saveToLocalStorage();
  habitTitle.value = "";
};

const changeToTransparent = (habit) => {
  if (cardRefs.value[habit.id] != null) {
    if (habit.ready) {
      cardRefs.value[habit.id].$el.style.backgroundColor =
        "rgba(170,193,200,0.25)";
      saveToLocalStorage();
    } else {
      cardRefs.value[habit.id].$el.style.backgroundColor = "";
      saveToLocalStorage();
    }
  }
};

onMounted(() => {
  // Load habits from localStorage
  // This is just an example
  habits.value = [
    {
      id: 0,
      title: "Testing new habit",
      ready: true,
    },
    {
      id: 1,
      title: "Testing new habit",
      ready: false,
    },
    {
      id: 2,
      title: "Testing new habit",
      ready: false,
    },
  ];
  counter.value = habits.value.length;
});
</script>
Sign up to request clarification or add additional context in comments.

1 Comment

note that you can also do changeToTransparent inside the template and simplify the code. By adding :style="{ background: habit.ready ? 'rgba(170,193,200,0.25)' : ''}" to q-card. Then you can remove the @click and click event and all code related to it.
2

Ok from the given context, I believe you're not using any backend and are saving all the entries on the local storage.

If that is the case, you must be storing your data in some array to LS like habits: []

Here instead of initiating counter to 0 you can add a lifecycle method.

beforeMount() {
  counter = JSON.parse(localStorage.getItem("habits")).length
}

3 Comments

and save counter value in localstorage on addHabit method
You are right that i am currently not using a backend and saving everything in Localstorage. I implemented your function and it is working if my habits array already exists. Thanks for yout help.
When your vue app mounts, you can create an empty array on LS so it will always exist.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.