Trouble with binding to an array inside a Vue component instance

Trying to grasp the concepts of vue.js, but struggling with a crucial element.

The goal is to create an accordion functionality for multiple boxes (only one box displayed at a time; opening a new box closes any previously open ones). Here's the current code:

<div id="app">

  <div class="block">
    <button v-on:click="mytoggle(0,$event)">block one</button>
    <div v-if="boxes[0]">
      <p>i am box number one</p>
      <p>i am box number one</p>
    </div>
  </div>

  <div class="block">
    <button v-on:click="mytoggle(1,$event)">block two</button>
    <div v-if="boxes[1]">
      <p>i am box number two</p>
      <p>i am box number two</p>
    </div>
  </div>

  <div class="block">
    <button v-on:click="mytoggle(2,$event)">block three</button>
    <div v-if="boxes[2]">
      <p>i am box number three</p>
      <p>i am box number three</p>
    </div>
  </div>

  <pre>{{ $data | json }}</pre>

</div>

and included script:

var vm = new Vue({
    el: '#app',

    methods: {
        mytoggle: function (n, event) {
            event.preventDefault();
            for(var i = 0; i < 3; i++) { // close all boxes
                this.boxes[i] = false;
            }
            this.boxes[n] = true; // open the corresponding box
            console.log(n);
        }
    },

    data: {
        boxes: [false,true,false]
    }
});

Upon loading the page, the second box is displayed (correct due to the true value in the second element of the boxes array).

However, clicking on the buttons does not update the boxes.array or display the boxes accordingly. The log output confirms the script is functioning correctly when buttons are clicked. It seems like there might be an issue with the binding process. Any guidance on resolving this would be greatly appreciated.

Answer №1

Give this a shot:

HTML:

<div id="content">

  <div class="box">
    <button @click.prevent="toggleBox(0)">Box One</button>
    <div v-show="boxes[0].isVisible">
      <p>This is box number one</p>
      <p>This is box number one</p>
    </div>
  </div>

  <div class="box">
    <button @click.prevent="toggleBox(1)">Box Two</button>
    <div v-show="boxes[1].isVisible">
      <p>This is box number two</p>
      <p>This is box number two</p>
    </div>
  </div>

  <div class="box">
    <button @click.prevent="toggleBox(2)">Box Three</button>
    <div v-show="boxes[2].isVisible">
      <p>This is box number three</p>
      <p>This is box number three</p>
    </div>
  </div>

  <hr/>

  <pre>{{ boxes | json }}</pre>

</div>

Vue:

var app = new Vue({
    el: '#content',
    data: {
        boxes: [{isVisible:false},{isVisible:true},{isVisible:false}]
    },
    methods: {
        toggleBox: function (index) {  
            for(var i = 0; i < 3; i++) { // close all boxes
                app.boxes[i].isVisible = false;
            }
            app.boxes[index].isVisible = true; // open the corresponding box
        }
    }
});

Fiddle: https://jsfiddle.net/username/123456789/

UPDATE:

You could also simplify your toggleBox method to modify array values using Vue's $set:

toggleBox: function (index, event) {
    event.preventDefault();
    for(var i = 0; i < 3; i++) { // close all boxes
        this.boxes.$set(i, false);
    }
    this.boxes.$set(index, true); // open the corresponding box
    console.log(index);
}

Answer №2

It is recommended to utilize the $set method instead of directly modifying data. [source]

You can also implement a simpler solution like the following:

new Vue({
  el: '#app',
  data: {
    selected: 1
  },
  methods: {
    select (index) {
      this.selected = index
    },
    isSelected (index) {
      return this.selected === index
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.24/vue.min.js"></script>

<div id="app">
  <div class="block">
    <button @click="select(0)">block one</button>
    <div v-show="isSelected(0)">
      <p>i am box number one</p>
      <p>i am box number one</p>
    </div>
  </div>

  <div class="block">
    <button @click="select(1)">block two</button>
    <div v-show="isSelected(1)">
      <p>i am box number two</p>
      <p>i am box number two</p>
    </div>
  </div>

  <div class="block">
    <button @click="select(2)">block three</button>
    <div v-show="isSelected(2)">
      <p>i am box number three</p>
      <p>i am box number three</p>
    </div>
  </div>
</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

Unable to add or publish text in CKEditor

In my ASP.NET MVC application, I am struggling to post the updated value from a CKEditor in a textarea. Here is the code snippet: <textarea name="Description" id="Description" rows="10" cols="80"> This is my textarea to be replaced with CKEditor ...

Utilizing d3.js to implement a scatterplot with zoom functionality that focuses solely on zooming the axis without affecting

Having trouble creating a scatterplot with zoom functionality where only the axis is getting zoomed, not the data itself. Can anyone provide some assistance or insight on what might be wrong? If you're interested in checking out the project, here&apo ...

Enquire.js does not compute accurately at first glance, but only after adjustments are made during

Currently, I am working on incorporating media queries using Enquire.js and Vue.js. The functionality seems to be in good shape when manually resizing the browser window. However, upon loading the document, no match is detected. This peculiar behavior beco ...

Utilizing JSON API data to populate Leaflet maps

I am currently working on fetching JSON data from an API call, extracting the latitude, longitude, and name variables to create a GeoJSON array, and then displaying it on a Leaflet map. Despite not encountering any errors in the console, the geojson appea ...

Display every div element if none of the links have been clicked

On my webpage at url.com/yourfirstpage/, all div elements are hidden by default with a display:none property. If we specifically target #sec1 by going to url.com/yourfirstpage/#sec1, only sec1 is displayed while the others remain hidden. But what if we acc ...

Tips for detecting successful file downloads from the client side using Mean/AngularJS

I have developed a chat application with the capability to send files through chat windows. I am now looking to automatically delete files from the server once they have been successfully downloaded by clients. My technology stack includes MEAN. rou ...

Issue: Exceeding rendering limit. React has a restriction on the number of renders to avoid endless loops

I'm in the process of creating a basic to do list using React, and I've encountered an issue with the handleSubmit() function that I can't seem to resolve. import React, { useState } from "react"; function TaskList() { const [ta ...

Utilizing TypeScript to Define Object Properties with String Keys and Values within Parentheses

I am in the process of developing a telegram bot I have the need to save all my messages as constants My message schema is structured as follows: type MessagesSchema = { [K in keyof typeof MessagesEnum]: string } Here is an example implementatio ...

Exploring the power of Vue with Cypress testing and streamlining the development process

Currently, I am facing a challenge while trying to run my E2E tests on Gitlab using their CI/CD platform. The issue I'm encountering is the inability to have both my development server and Cypress running simultaneously in order for the E2E tests to ...

The implementation of Typescript in Express does not rely on Middleware

I've encountered an issue with my Auth Middleware - it seems that the middleware isn't being called at all. Even when I intentionally throw an Error within the middleware function, nothing is printed out. For testing purposes, I only need to inv ...

Issue: NextRouter is not mounted when the client is used

After implementing use client, I encountered the following error: Error: NextRouter was not mounted error. However, upon removing use client, a different error surfaced: Error when use client is removed: ReactServerComponentsError: A component requirin ...

What could be causing the issue of receiving the error message: "Uncaught TypeError: Cannot read property 'Title' of undefined"?

I am currently working on developing an AJAX web application. One of the functions I have is aimed at requesting a JSON object and then utilizing it to refresh the website content. Below is the portion of JavaScript causing an issue (Lines 8 - 16): windo ...

I am looking for a way to hide email addresses using Regex in JavaScript

I'm looking for a way to hide an email address [email protected]=> [email protected] using JavaScript I attempted to use the /(?<=.{2}).(?=[^@]*?@)/ regex, but it is not functioning properly in Internet Explorer and Mozilla. I need a ...

What is the best way to access the URLs of files within a Google Drive folder within a React application?

I've been working on a react app that's relatively straightforward, but I plan to add a gallery feature in the future. To keep things simple for the 'owner' when updating the gallery without implementing a CMS, I decided to experiment ...

Guide to retrieving a string value rather than Json output with a mongodb aggregate function

I have a function that retrieves the value of the 'minHospitalization' field from the database. The response from this function is '[{"minHospitalization":1}]' Instead of returning the value in JSON format, I want to return just ' ...

Obtaining the HTML content of a div element that has been retrieved through an AJAX request to a PHP script

My challenge is to fetch a dropdown menu from a server and then manipulate it using jQuery after loading. Although everything loads correctly, I am unable to interact with the dropdown items because they were dynamically added post AJAX response instead of ...

Can two Vue.js applications coexist on the same URL?

My current project involves a client who wants users to visit a single URL and then have PHP detect their device in order to provide them with a specific Vue js app. However, the client is insistent that all users, regardless of device or app, must access ...

Modify the value of select options when the page is first loaded

I want to set up a dropdown menu with a list of regions, and I need the drop down to automatically select an option based on the variable value that I assign. Here is the code snippet. <select name="_sft_location[]" class="sf-input-select" title=""&g ...

Limiting the dropdown results in v-autocomplete: A simple guide

Image Link After receiving 100-200 results from the axios api, I am looking for a way to display only the first 10 items. However, I also need to show the total count of all items retrieved. Unfortunately, this cannot be achieved directly from the api call ...

How can I customize a default button in HTML to hide the selected option from the dropdown menu?

Hey there! I'm currently working on a website that needs to be bilingual, with Spanish as the default language. I want to include a dropdown button that allows users to translate the content into English. Here's what I've tried so far: ...