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

I'm baffled by the constant undefined status of the factory in AngularJS

I have encountered an issue where I defined a factory that makes a get request, but when I inject it into a controller, it always throws an undefined error. Below is the code for the factory: (function() { 'use strict'; var app = angul ...

Could anyone clarify the workings of the async function in this specific useEffect situation?

Within a child component, there is an onClick event: onClick={()=>{ //2. an image is clicked, and the choice is added to the choiceOrder state, and then a jsonupdate is called -- 3. in ChooseBy.js //onclick, add or remove the choice choosebyprop ...

How to Detect Font Resizing in Google Web Toolkit (GWT)

I am trying to find a way in GWT to capture the font resize event that occurs when the user changes the size of the font by using Ctrl-Mouse Scroll or going to View -> Zoom. I have searched on Google and looked on StackOverflow but haven't found any i ...

The ClearInterval() function does not take effect instantly

I've implemented a Carousel with an auto-toggle feature using the setInterval() function to switch between tabs every 4 seconds. However, I now need to stop this automatic toggling when a specific tab is clicked. You can find the HTML and jQuery for ...

When attempting to use jQuery to click on a button that triggers an ajax callback, the functionality does not

I am facing an issue with my Drupal website. I have created a form with a button that has an ajax callback. The callback works perfectly, but now I want to execute a small JavaScript function when the user clicks on the submit button. Instead of creating ...

Utilizing Route Parameters in Node.js

frontend.jade doctype html html head meta(charset='utf-8') //if lt IE 9 script(type='text/javascript', src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js') // [if gte IE 9] <! scr ...

Need help triggering Ajax code upon clicking a link?

Can someone help me find the issue with my script? Below is the code snippet: <script> $(".icross").click(function(e){ e.preventDefault(); var obj = $(this); $.ajax({ type: "GET", url: "supprimer.php", data: 'id=&a ...

Unlocking the power of array destructuring in Nuxt's asyncData when working with Promise.all

Currently, I am delving into the world of Nuxt and Vue along with a MySQL database. These technologies are relatively new to me as I make the transition from WebMatrix. In my previous setup, I had a single Admin page that handled multiple tables with dro ...

Guide on utilizing VueJS plugins in the browser without any added layers

I have decided to incorporate VueJS into an old system instead of using JQuery. However, I am facing difficulties in utilizing plugins like I would with JQuery. For instance, when trying to import the "vuetable" library directly into my HTML using script t ...

Accordion menu causing Javascript linking problem

After following a tutorial, I managed to create an accordion menu in JavaScript. In the current setup, each main li with the class "ToggleSubmenu" acts as a category that can hide/show the sub-lis. Now, my query is this: How can I retain the link functio ...

Sort an array by mapping it in decreasing order based on the total sum of its elements

I came across a JSON structure that looks like the following: { "user": [ {"username": "x1", "pfp": "", "scores": [{"easy": 10, "normal": 1, "hard": 2, "oni&q ...

What is the method for ensuring text remains within a square while it is being relocated?

Check out this jsfiddle where you can interact with a moving square: http://jsfiddle.net/helpme128/3kwwo53t/2/ <div ng-app="test" ng-controller="testCtrl"> <div id="container"> <div class="shape" ng-draggable='dragOptions& ...

Error occurred in the middle of processing, preventing the headers from being set

I created a custom authentication middleware, but encountered an error. I'm puzzled about what's going wrong because I expected the next() function to resolve the issue? app.use(function(req, res, next){ if(req.user){ res.local ...

Tips for waiting for an HTML element to load in a Selenium JavaScript testing script

I'm struggling to find a way to wait for an element to load in a javascript selenium test script. The closest thing I've come across is until.elementLocated, but it seems to throw an immediate exception. Is there a method to delay throwing the " ...

Vue disregards redundant data duplication

I'm still new to Vue and I'm working on removing data repetition in my array objects. VIEW <div id="app"> <h2>Programming Classes Time</h2> <div v-for="todo in todos"> <p>{{todo.time}}</p> /** Lookin ...

Steps for efficiently incorporating a template within another template

Just starting out with VueJS... I'm trying to figure out a way to dynamically add other components into a main component based on the dropdown selection. The main template always remains on the screen and includes a dropdown. What I want is to have a ...

Running an Angular-made Chrome extension within an iframe: A guide

I'm currently working on creating a Chrome extension that displays its content in a sidebar rather than the default popup. I've come to realize that in order to achieve this, I need to use an iframe due to the limitations of the default chrome ex ...

Error encountered: The Bootstrap Carousel function is causing a TypeError as e[g] is not defined

I am attempting to build a dynamic bootstrap carousel using my json data, and I have implemented jQuery-Template for rendering. Essentially, I am generating the carousel slider on-the-fly from my json data with the help of jQuery-Template. Here is a snippe ...

Creating a dynamic list filter using JavaScript and three select boxes

Looking for a way to implement a similar feature to the one on this webpage: I will be showcasing a list of brands on the page, with each brand requiring three pieces of information: Starting letter Store (multiple options) Category (multiple options) ...

"Exploring the power of Knockout JS by utilizing the foreach loop to iterate through

I have an observableArray: self.stats = ko.observableArray([ {"DFTD" : new Stat("Defensive TD", "DFTD",0,20,0,self.playerGroups[1])}, {"GL" : new Stat("Games Lost", "GL",0,16,0,self.playerGroups[2])}, {"FGA" : new Stat("Field Go ...