v-show is not functioning properly

After clicking the button, I notice that even though the array shows[] changes (as indicated by Vue's chrome plugin), the character 'a' remains on the page. However, characters 'b' and 'c' do not appear at all.

<script type="text/javascript" src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7402011134465a415a4542">[email protected]</a>/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
        currentShow:0,
        shows:[true, false, false],
        },
        watch:{
            currentShow: function (val, old) {
                this.shows[old] = false;
                this.shows[val] = true
            }
        }
    });
</script>
<!-- Letter 'a', 'b', 'c' will only show when their corresponding shows[] value is true-->
<div id="app">
    <p v-show="shows[0]">a</p>
    <p v-show="shows[1]">b</p>
    <p v-show="shows[2]">c</p>
    <button @click="currentShow=(currentShow+1)%3">next</button>
</div>

Answer №1

That's a word of caution when it comes to reactivity. One workaround is to utilize the Vue.set() method:

<script type="text/javascript" src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2254574762100c170c1314">[email protected]</a>/dist/vue.js"></script>

<!-- Letter 'a', 'b', 'c' shows only when its corresponding shows[] is true-->
<div id="app">
    <p v-show="shows[0]">a</p>
    <p v-show="shows[1]">b</p>
    <p v-show="shows[2]">c</p>
    <button @click="currentShow=(currentShow+1)%3">next</button>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            currentShow: 0,
            shows:[true, false, false],
        },
        watch:{
            currentShow: function (val, old) {
                Vue.set(this.shows, old, false);
                Vue.set(this.shows, val, true);
            }
        }
    });
</script>

Read more in the Docs:

If you are making modifications or additions based on an index, remember to use Vue.set():

Vue.set(this.shows, old, false);
Vue.set(this.shows, val, true);

Alternatively:

this.shows.splice(old, 1, false);
this.shows.splice(val, 1, true);

This approach helps Vue maintain reactivity for that specific element.

The Reasoning Behind It

Alongside the typical caveat issues, the documentation provides specific advice regarding arrays:

Caveats

Due to JavaScript limitations, Vue cannot detect these types of changes within an array:

  1. Directly setting an item using the index, e.g., vm.items[indexOfItem] = newValue
  2. Adjusting the length of the array, e.g., vm.items.length = newLength

For example:

var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // does NOT trigger reactivity
vm.items.length = 2 // does NOT trigger reactivity

To address issue 1, both methods below achieve the same outcome as vm.items[indexOfItem] = newValue, and also prompt state changes within the reactivity system:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)

// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

You can also utilize the vm.$set instance method, which serves as a shorthand for the global Vue.set:

vm.$set(vm.items, indexOfItem, newValue)

To tackle issue 2, utilize the splice method:

vm.items.splice(newLength)

Answer №2

Vue is unable to watch array elements if they are primitives, as it relies on methods like push() and pop() to trigger updates rather than tracking individual value changes. Check out the documentation for more details.

I have come up with a specific solution tailored to your example, which involves selecting only one item at a time. Feel free to customize it as needed.

let vm = new Vue({
    el: '#app',
    data: {
      currentShow: 0
    },
    methods: {
    
      showNext(){
        this.currentShow = (this.currentShow+1) % 3
      }
      
    }
});
<script type="text/javascript" src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c2b4b7a782f0ecf7ecf3f4">[email protected]</a>/dist/vue.js"></script>

<!-- Letter 'a', 'b', 'c' shows only when its corresponding shows[] is true-->
<div id="app">
    <p v-show="currentShow==0">a</p>
    <p v-show="currentShow==1">b</p>
    <p v-show="currentShow==2">c</p>
    <button @click="showNext()">next</button>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The Gatsby and React navigator

Hey there, I've run into a little snag while working on my React component. I'm trying to display a pop-up using JS, but when I try to build my Gatsby site, I encounter an error stating: WebpackError: ReferenceError: navigator is not defined. Bel ...

Refining a selection from a list using a multi-choice array

I have a filtering component that filters a list of people based on multiple input values. The string-based inputs filter properly, but when I select more than one item in the multi-select, nothing is displayed. This is likely due to person.role not contai ...

What is the process for including an external .js file in my VueJS2 index.html?

Currently, I am faced with a challenge involving two external Javascript files that are responsible for managing animations and vector triangulation for a background animation. In a typical html/css/js project, adding these two .js files would involve incl ...

Enhance your website with the latest jQuery plugins and CSS

Currently, I am utilizing jQuery to develop plugins for my application. It is worth noting that each plugin demands a distinct CSS file. What approach should I follow to effectively load both the jQuery file and the respective CSS? Moreover, the plugins ...

The audio.play() HTML element fails to function in Chrome, preventing the audio from playing

I'm experiencing an issue with playing audio in Chrome when the audio.src is not called before the play call, but Firefox seems to handle it fine. Does anyone have any suggestions? You can check out the fiddle link below - http://jsfiddle.net/vn215r2 ...

The antithesis of a feature that encapsulates a chosen area with a span

Hi everyone, I have a function that works as follows: define(function () { 'use strict'; var sel, range, span; return function () { span = document.createElement("span"); span.className = 'highlight'; if (window.ge ...

Using Jquery to encase an element in a div while scrolling down and removing it while scrolling up

After some experimentation, I've managed to wrap an element inside a div using jQuery. My next challenge is to wrap it as you scroll down and unwrap it as you scroll up. Do you think this is achievable? Although I have succeeded in wrapping it while ...

Initially display checkboxes for selecting items using a custom row template in V-data-table

I have implemented a custom template for each row in a v-data-table, and I am encountering an issue with checkboxes. When using :value="item", all checkboxes are initially checked, which is not the behavior I want. I am unsure of how to approac ...

Excluding specific e2e tests in Protractor: A guide

I have a collection of end-to-end tests for my AngularJS web application. Here is the configuration in my current protractor.config.js file: // __dirname fetches the path of this specific config file // assuming that the protractor.conf.js is located at t ...

Generating fresh objects to establish a Many-to-Many connection with Sequelize

I am currently utilizing NodeJS, Express, Sequelize, and PostgreSQL in my project. Within my application, I have defined two models: a "User" model and a "Social" model. My goal is to establish a many-to-many relationship where a user can be associated wi ...

Tips on customizing label colors on a Donutchart using Google API

https://i.sstatic.net/Rpor0.png I am looking to change the color of 12.5 (to Green) and 25 (to red) based on the donut arc color in Google Charts. Below is the code snippet: var container = document.getElementById('chart_div'); var chart = new ...

AngularJS: splitting the parent <div> into multiple sections every nth element

I have an array of strings in Javascript and I am attempting to use AngularJS to create nested <div> elements. var arr = ["abc", "def", "ghi", "jkl", "mno", "pqr", "stu"]; My goal is to group every 3 elements together like so. <div class="pare ...

Is it possible to merge a string with a variable using v-model?

After exploring various solutions for a similar issue like this, I am still unable to make my template compile successfully. The challenge lies in concatenating a string with a variable within v-model to bind to an array inside an object: <li v-for=&qu ...

Is it possible to transfer elements from one array to another when clicked, but without copying the contents to the new array objects?

Welcome, For my latest project, I am excited to create a "Learning Cards" App from scratch. The concept is pretty straightforward: it consists of cards with questions. Upon clicking a button, you can reveal the correct answer. Additionally, there's a ...

Testing vue-router's useRoute() function in Jest tests on Vue 3

Struggling with creating unit tests using Jest for Vue 3 components that utilize useRoute()? Take a look at the code snippet below: <template> <div :class="{ 'grey-background': !isHomeView }" /> </template> &l ...

Interactive game created using JavaScript input

I've scoured the internet for guidance on creating a text-based game that utilizes user input, but all I come across are tutorials focusing on button interactions. What I envision is triggering different responses based on specific user inputs. For i ...

Utilizing the Google Translate API within an ASP MVC framework to translate a div's content from English to Arabic

Currently, I am working on a small project that involves two divs: one for English and another for Arabic. Despite creating the project, I am encountering an issue with getting the translation from English to Arabic. Below is the code I have attempted, but ...

Delivering an XML file generated by PHP to a JavaScript parser

I'm in the process of creating a smart TV app that streams live content. The app functions properly when I provide it with a valid XML playlist. However, when I attempt to use PHP to generate the XML file (which generates without any issues), it fail ...

The 'disabled' property is not found in the 'MatButton' type, however, it is necessary in the 'CanDisable' type

Issue found in node_modules/@angular/material/core/option/optgroup.d.ts: Line 17: Class '_MatOptgroupBase' does not correctly implement interface 'CanDisable'. The property 'disabled' is missing in type '_MatOptgroupBas ...

Achieving Full Height for Parallel Columns Divs with Bootstrap - A How-To Guide

I am struggling with getting two divs in parallel to have full height. Even though I have the divs side by side, when I try to set their height:100%;, nothing happens. What CSS properties do I need to modify to achieve this? The goal is to create a cove ...