Search code examples
jqueryvue.jsv-for

Cant assign class in Vue js for list - bug or limitation?


I am migrating a site from jquery to vue js and while in general its ending up much cleaner and simpler than the jquery version, i am hitting some obstacles which don't seem to be easily solved by Vue js.

A specific problem I am having is that I am generating a long list of ui elements. Clicking on these elements should switch the element color. In jquery this was simply a matter of putting a listener on the class that appears on these elements and then toggle an 'active' class on the element.

In Vue its not so simple.... I am use v-for to build the list and have to create an array which holds the list of objects which define the data I need to store on these elements...something like the following...

               this.timeblocks = [];
               for (var j = 1; j < 25; j++) {
                    var id = 'iam'+ i + '_'+ j + '';
                    var block = {id: id, val: false,zone:'mid',  time: this.getTime(j) + ' AM'};

                    this.timeblocks.push(block);
               }

I now generate the list based on this data object as follows:

<a class="mid" v-for="(obj, index) in timeblocks" :id="obj.id" :data-value="obj.time" :class="{'active':obj.val}"  @click="toggleTime(obj,$event)"></a> 

I would have expected that I could have just created a click event like this

@click="obj.val = !obj.val"

This would have toggled the object value from false to true which should have toggled the 'active' class. It seems to work but only once, ie for only one element and will only toggle once. I see the data changing but the css is not being applied.

Does anyone know what is causing this?

Instead I currently have to use jQUery and called a toggleTime method on the click event which looks as follows:

   toggleTime: function(obj,event) {
        console.log('Toggle time:',obj);
        //obj.val = !obj.val;
        $("#" + event.currentTarget.id).toggleClass('active');
    },

I really don't want to have to use jquery and want to understand why Vue is just not working in this case.

Would appreciate any guidance or comments. Thank you!

UPDATE

The selected answer below works. But I wanted to point out that the issue is something I left out of the original question.

I am actually using timeblocks as an array of arrays, being populated as follows:

this.timeblocks = [];
            for (var i = 1; i < 8; i++) {
                this.timeblocks[i] = [];
                for (var j = 1; j < 25; j++) {
                    var id = 'iam'+ i + '_'+ j + '';
                    var block = {id: id, val: false,zone:'mid',  time: this.getTime(j) + ' AM'};

                    this.timeblocks[i].push(block);


                }
                for (var j = 1; j < 25; j++) {
                    var block = {};
                    var id = 'ipm'+ i + '_'+ j + '';
                    var block = {id: id, val: false, zone:'noon', time: this.getTime(j) + ' PM'};
                    this.timeblocks[i].push(block);

                }
            }

When I reference one of these (as per below) is when it does not work. Unless I implement the nextTick fix from Luis (above)

  <a class="mid" :id="obj.id" v-for="(obj, index) in timeblocks[1]" :data-value="obj.time" :class="{'active':obj.val}"  @click="clicktime(obj)">{{obj.id}}</a>

Note above I am using timeblocks[1] in the v-for and not just timeblocks. This seems to be the reason that it breaks but I am unclear why?

See here https://codepen.io/anon/pen/WyQmMM?editors=1011

Any ideas?


Solution

  • Try rendering your list view (update) in your click method

    <a v-show="this.showList" ...></a>
    
    updateUI() {
      this.$nextTick(() => {
        this.showList = false;
        this.$nextTick(() => {
          this.showList = true;
        });
      });
    }