1
votes

I'm having a weird behavior from the Vuetify componentv-checkbox.

  • Steps to reproduce

The codepen shows 3 checkboxes per array element. I want to read the actual state of the checkbox (true or false) near each checkbox. Change the checkboxes's state and see it is being displayed correctly. Then, remove the line {{ counter }} and check again.

  • Expected Behavior

If you check a checkbox, it has to show 'true', and viceversa, if you uncheck it, it has to show 'false'. 'false' is the default value.

Actual Behavior

  • If a counter {{ counter }} that I'm using for the number of checks/unchecks is being printed in HTML, the state of the checboxes are working showing correctly. If not, the states remains in the default value.(nevertheless, if I console.log it, they appear to be changed).

This is my code: - HTML:

 <div id="app">
  <div v-for="(row, index) in rows" :key="index">
    <v-layout row wrap>
      {{ row.item }}: 
      <v-card flat v-for="(friend, idx) in row.friends" :key="`msg-${idx}`">
        <v-checkbox
           v-model="friend.selected"
           :label="friend.name"
           color="red"
           hide-details
           @click.native="counter++"
        ></v-checkbox>
        {{ counter }}
        {{ friend.selected }}
      </v-card>
    </v-layout>
    <v-divider :key="`divider-${index}`"></v-divider>
  </div>
</div>
  • Vue
new Vue({
  el: "#app",
  data () {
    return {
      friendsAdded: ['Friend 1', 'Friend 2', 'Friend 3'],
      items: ['Place 1'],
      counter: 0,
    }
  },
  methods: {
    updateStatus(friend) {
     // Do something later
    },
  },
  computed: {
    rows() {
      const rows = [];
      for(let i = 0; i < this.items.length; i += 1) {
        const row = {};
        row.item = this.items[i];
        row.friends = [];
        for(let j = 0; j < this.friendsAdded.length; j += 1) {
          const friend = {};
          friend.name = this.friendsAdded[j];
          friend.selected = false;
          row.friends.push(friend);
        };
        rows.push(row);
      }
      console.log('rows: ', rows);
      return rows;
    }
  },
})

Here is codepen: https://codepen.io/rodrigoabb/pen/wYgzWW?editors=1010

Am I doing something obscenely wrong? How can I achieve the expected behavior without have to read that value (or something else)?

Thanks!

1
I don't understand what you are expecting to happen. The code seems to work as it is written. Are you saying you want the counter values to only count the number of time the corresponding checkbox was checked? So if the first box is checked 10 times and the others 0 times, then it would read 10, 0, 0?Justin Kahn
Sorry, may be I didn't explain myself clearly. I wanted to know why, when I read the counter (in the div), the text that shows the state (true or false) is updated, and when I delete the div of the counter, the state doesn't updateRodrigo.A92

1 Answers

4
votes

One thing is wrong with your approach:

You are trying (by using v-model binded to friend.selected, which gets and also sets value) to set value of a computed property (the rows).

This is basically wrong: https://vuejs.org/v2/guide/computed.html#Computed-Setter

What happens is:

The template was not sensitive to the change, although it actually occurs on the friends object. (Vuejs won't warn you about it because it is on a deep level of the computed object)

So, a re-render of your component never happened. But if that {{counter}} exists, that {{counter}} will be the sole reason for the re-render, which renders the whole template, including the {{friend.selected}}

With your simple case you can use the data function to create the rows array. Other options will be using separate data property to bind with the v-model, which will then affect the main rows array with watcher (if needed) or to use computed setter.

Example: Use data:

new Vue({
  el: "#app",
  data () {
    let items = ['Place 1'];
    let friendsAdded = ['Friend 1', 'Friend 2', 'Friend 3'];
    const rows = [];
    for(let i = 0; i < items.length; i += 1) {
      const row = {};
      row.item = items[i];
      row.friends = [];
      for(let j = 0; j < friendsAdded.length; j += 1) {
        const friend = {};
        friend.name = friendsAdded[j];
        friend.selected = false;
        row.friends.push(friend);
      };
      rows.push(row);
    }
    console.log('rows: ', rows);
    return {
      friendsAdded,
      items,
      counter: 0,
      rows
    }
  },
  methods: {
    updateStatus(friend) {
     // Do something later
    },
  },
})