Data binding in Vue.js seems to be malfunctioning

I'm having trouble with my Vue component creation. I've been using v-show to hide certain elements, but it doesn't seem to be working as intended.

The goal is to hide an element when clicked from a list by setting element.visible to false in the click event. However, binding this value to v-show in the component template doesn't result in the element being hidden.

I suspect that the issue may stem from element.visible being a nested attribute, but I can't say for sure.

var collection = [
        { id: 1, name: 'element 1' },
        { id: 2, name: 'element 2' },
        { id: 3, name: 'element 3' },
        { id: 4, name: 'element 4' },
        { id: 5, name: 'element 5' },
        { id: 6, name: 'element 6' },
        { id: 7, name: 'element 7' },
        { id: 8, name: 'element 8' },
      ];

var multiselect = {
  props: ['collection'],
  data: function() {
    return {
      subscribed: [],
      toSubscribe: [],
      toUnsubscribe: [],
      dataset: []
    }
  },
  mounted: function(){
  this.dataset = _.map(this.collection, function(element){
    element.visible = true;
      return element;
    });
  },
  methods: {
    subscribe: function(element){
element.visible = false;
    }
  }

}

new Vue({
  el: '#app',
  components: {
    'multiselect': multiselect
  },
  data: {
    elements: collection
  }
})
.multiselect .list {
  border: 1px solid #000;
  height: 215px;
  max-height: 215px;
  overflow: scroll;
}
.multiselect .list .list-element {
  text-align: center;
  padding: 0.2em;
  cursor: pointer;
}
.multiselect .list .list-element:hover {
  background-color: #d6dbdf;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8ee2e1eaeffde6cebaa0bfb9a0ba">[email protected]</a>/lodash.min.js"></script>
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bdcbc8d8fd8f9388938c8e">[email protected]</a>/dist/vue.js"></script>



<div id="app">

  <multiselect inline-template :collection="elements">
    <div class="col-sm-12 multiselect">

      <div class="col-sm-5 list">
        <div class="col-sm-12">
          <div v-for="element in dataset" class="list-element" @click="subscribe(element)" v-show="element.visible">
            {{element.name}}
          </div>
        </div>
      </div>

      <div class="col-sm-2">
        <button class="btn btn-primary btn-fill">
          <i class="fa fa-arrow-right" aria-hidden="true"></i>
        </button>

        <button class="btn btn-primary btn-fill">
          <i class="fa fa-arrow-left" aria-hidden="true"></i>
        </button>
      </div>

      <div class="col-sm-5 list">

      </div>

    </div>
  </multiselect>


</div>

Answer №1

One interesting approach is to avoid cloning the collection elements or setting a property on them.

Instead, you can maintain a parallel array of flags, but it's important to pay attention to the syntax for updating them and ensure that the flag is encapsulated within an object to make it observable.
For example, an array of { visible: true } rather than just true.

Reference: Mutation Methods

var collection = [
  { id: 1, name: 'element 1' },
  { id: 2, name: 'element 2' },
  { id: 3, name: 'element 3' },
  { id: 4, name: 'element 4' },
];

var multiselect = {
  props: ['collection'],
  data: function() {
    return {
      visibleFlags: []
    }
  },
  created: function(){
    this.collection.forEach(x => {
      this.visibleFlags.push({visible: true});  // Vue mutation method
    })
  },
  methods: {
    subscribe: function(index){
      this.$set(this.visibleFlags, index, false)
    }
  }
}

new Vue({
  el: '#app',
  components: {
    'multiselect': multiselect
  },
  data: {
    elements: collection
  }
})
.multiselect .list {
  border: 1px solid #000;
  height: 125px;
  max-height: 215px;
  overflow: scroll;
}
.multiselect .list .list-element {
  text-align: center;
  padding: 0.2em;
  cursor: pointer;
}
.multiselect .list .list-element:hover {
  background-color: #d6dbdf;
}
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7107041431435f445f4042">[email protected]</a>/dist/vue.js"></script>
<div id="app">
  <multiselect inline-template :collection="elements">
    <div class="col-sm-12 multiselect">
      <div class="col-sm-5 list">
        <div class="col-sm-12">
          <div v-for="(element, index) in collection" 
            class="list-element" v-show="visibleFlags[index].visible" 
            @click="subscribe(index)">
            {{element.name}} 
          </div>
        </div>
      </div>
    </div>
  </multiselect>
</div>

Answer №2

The issue arises when attempting to modify an object that is already responsive. Vue is unable to detect property additions.

This problem is masked by using the map method to copy and assign it to a new array. However, this new array contains references to responsive objects, each with the added visible property. This results in the parent data items also receiving the visible property.

To resolve this, a simple solution is to utilize Object.assign to create a new object and transfer properties into it. This ensures all properties are inserted into a non-responsive object, which becomes responsive upon assignment.

  mounted: function(){
    this.dataset = _.map(this.collection, function(element){
      return Object.assign({}, element, {visible: true});
    });
  },

If the DOM element is not required, you could alternatively implement this in the created method.

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

Vue 3 - Non-reactive object properties

How do I ensure that userInfo.value.email is reactive in this Vue3 component: <script setup> import { useUserStore } from '../store/user'; import { storeToRefs } from "pinia"; const userStore = useUserStore() const ...

Contrast between categories and namespaces in TypeScript

Can you clarify the distinction between classes and namespaces in TypeScript? I understand that creating a class with static methods allows for accessing them without instantiating the class, which seems to align with the purpose of namespaces. I am aware ...

Tips for implementing a document ready function on a nested page within a larger full-page website

I am currently working on a website that utilizes fullpage.js, but the same principle applies to all single-page websites. I am trying to figure out how to implement the $(document).ready() function on a 'nested' page within the site. Since every ...

jQuery is implemented prior to the completion of HTML loading

Is there a way to ensure that HTML content loads before executing a JavaScript function? $(document).ready(function() { var x = 10; if(x == 10) { $('h1').text("Its changed !"); alert("Test"); } }) <h1>Hello< ...

Issue Arising from Printing a Custom Instruction in a Schema Generated Document

When dynamically adding a directive, the directive is correctly generated in the output schema. However, it seems to be missing when applied to specific fields. Here is how the directive was created: const limitDirective = new graphql.GraphQLDirective({ na ...

The attempt to generate a .zip file using Node.js with Egg framework was unsuccessful

I developed a Node.js service using Egg framework to send a local .zip file (compressed directory) to the browser, but encountered an issue. Below is the code snippet: Egg.js // Code for zipping files async download() { const ctx = this.ctx; co ...

Guidance that utilizes the scope of a specific instance

I have successfully created a d3.js directive, but I am facing an issue when resizing the window. The values of my first directive seem to be taking on the values of my second directive. How can I separate the two in order to resize them correctly? (both ...

Navigating through a dropdown menu using Selenium in Javascript for Excel VBA - Tips and tricks

I need to access a web page using Excel VBA that is only compatible with Chrome or Firefox, not Internet Explorer. I have successfully accessed the website using Selenium, but I am having trouble navigating through the drop-down menu to reach the section w ...

JavaScript and HTML - specify the location in the html document where the JavaScript script will be displayed

I'm a beginner when it comes to JavaScript. I am trying to make sure that my HTML page remains unchanged while JavaScript text is displayed in a specific location without refreshing the entire page. To trigger a JavaScript function via a button on a ...

How can I apply and delete a css class only while scrolling in a React application?

Currently, I am designing a pretend blog layout to showcase my work. The grid of posts features cards that are precisely 400x400 in size with a hover effect that magnifies and adds a drop shadow (this is visible in the dashboard route). However, an issue ...

Unexpected failure when using FormData in Ajax callback for large files

I have a file upload control where I can upload various types of files. After getting the file, I store it in a FormData object and make an ajax call to my controller. Everything works well with images and small .mp3 files. However, when I try to upload .m ...

Leveraging the power of AngularJS' ngAnimate for smooth transitions when deleting an item from the scope

I have a basic question: How can I utilize ngAnimate in AngularJS 1.2.x to trigger animations when removing an item from the scope? Here is an example Plunker for reference: http://plnkr.co/edit/tpl:FrTqqTNoY8BEfHs9bB0f?p=preview Code snippet: <bo ...

What is the best way to extract plain text with JQuery?

I found this Html code snippet: <div class="form-group row"> <label id="lb_size" class="col-lg-3 col-form-label"> <span class="must-have">****</span> Size </label> </div> My goal is to ext ...

Is It Possible to Extract a Hidden Document Value from a Web Browser Using IWebBrowser2 in LabVIEW?

After hours of combing through the internet, I've come up empty-handed in my quest to find information related to my current project. I've created an HTML document that gathers user data and stores it in a JavaScript array. This array is then com ...

serializeArray encounters difficulty in locating certain input elements

I've created this HTML layout: <div class="col-md-12"> <div class="form-group"> <label>Mini description (displaying the latest added destinations and meta description)</label> <textarea class="for ...

Identify and troubleshoot scripts that are included in the response returned by Chrome

I am facing an issue where I have a webpage that loads HTML sections through an AJAX call. The response includes both HTML and JavaScript files. Currently, I am trying to figure out how to set a debug point on the JavaScript file. In Internet Explorer, I ...

Utilize React Redux to send state as properties to a component

When my React Redux application's main page is loaded, I aim to retrieve data from an API and present it to the user. The data is fetched through an action which updates the state. However, I am unable to see the state as a prop of the component. It s ...

Struggling with navigating JSON data in JavaScript and facing difficulties sorting the array

I am currently facing the challenge of organizing data obtained from an API using JavaScript. JavaScript Code to Retrieve Data: function getResults() { var url = $.getJSON("http://api.api.com&leagues=SOCENGPRE&lang=en&format=jsonp&cal ...

Eliminable Chips feature in the Material UI Multiple Select component

The Material UI documentation showcases a multiple select example where the selected options are displayed using the Chip component and the renderValue prop on the Select. By default, clicking on the current value opens the list of available options. I am ...

What are some ways to implement querySelectorAll in conjunction with htmx?

I'm currently using htmx, an amazing library with a small issue that I'm struggling to resolve. htmx utilizes querySelector to find elements for swapping or updating, for example with hx-swap="...", hx-target="...". How can I use querySelectorAll ...