VueJS does not refresh the list items when changes are made from components

Facing an issue with rendering an array from vuex using "v-for".

The "player-card" component is not being displayed, however, the "td" solution is functioning correctly.

Check out my example on JSFiddle.

HTML:

    <div id="app">
      <button v-on:click="moveItem">
        Move Item
      </button>

      <table cellspacing="2" border="1" cellpadding="5">
        <tr>
          <td v-for="(item, item_idx) in getItems" v-bind:key="item.col">{{ (item.card)? item.card.name : 'none' }}</td>
        </tr>
        <tr>
          <player-card v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></player-card>
        </tr>
      </table>
      <br/>
      <p>{{msg}}</p>
    </div>

Store:

    const store = new Vuex.Store({
      state: {
        items: [{ col: 0, row: 0 },
                { col: 1, row: 0 },
                { col: 2, row: 0, card: { name: "hello" } } ]
      },
      getters: {
        getterItems: state => { return state.items; }
      },

      mutations: {
        MOVE_ITEM: state => {
          state.items[0].card = state.items[2].card;
          delete state.items[2].card;
          state.message = JSON.stringify(state.items);
        }
      }

    });

Component:

    Vue.component('player-card', {
      props: {
        item: {
          type: Object,
          required: true
        }
      },
      template: '<td>{{ (item.card)? item.card.name : "none" }}</td>'
    });

App:

    new Vue({
      el: '#app',
      store,
      data: function() {
        return {
          msg: ''
        }
      },
      computed: {
        getItems() { return this.$store.getters.getterItems; }
      },
      mounted: function() { 
        this.msg = JSON.stringify(this.getItems); 
      },
      methods: {
        moveItem() {
          this.$store.commit('MOVE_ITEM');
          this.msg = JSON.stringify(this.getItems);
        }
      }
    });

I have explored various solutions but have yet to find a simple one. Perhaps someone can suggest a different architectural approach.

Answer №1

Make a simple adjustment to this line:

<player-card v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></player-card>

Change it to this:

<td is="player-card" v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></td>

It's necessary because the template is specified within the DOM. The browser will interpret the template markup before Vue processes it. According to HTML parsing rules, only certain elements can be direct children of a <tr>. Any other element will be removed from the <table>. By the time Vue attempts to parse the template, the <player-card> element will have already been relocated outside the <table>.

This issue wouldn't arise if you utilized another method to define the template.

The solution is to use the is attribute to specify the component instead of the tag name.

You can find more information about this in the documentation here:

https://v2.vuejs.org/v2/guide/components.html#DOM-Template-Parsing-Caveats

Answer №2

To overcome the expected element structure within <tr> where <td> are required as children but <player-card> is being used (pre-transformed), you must utilize the special is property. Moreover, the reactivity issues stem from how you are altering your Array. I suggest implementing my proposed solution.

const store = new Vuex.Store({
  state: {
    items: [{
        col: 0,
        row: 0
      },
      {
        col: 1,
        row: 0
      },
      {
        col: 2,
        row: 0,
        card: {
          name: "hello"
        }
      }
    ]
  },
  getters: {
    getterItems: state => {
      return state.items;
    }
  },

  mutations: {
    MOVE_ITEM: state => {
      // Move the last element to the front
      state.items = [
        ...state.items.slice(-1),
        ...state.items.slice(0, -1)
      ];
      state.message = JSON.stringify(state.items);
    }
  }

});

Vue.component('player-card', {
  props: {
    item: {
      type: Object,
      required: true
    }
  },
  template: '<td>{{ (item.card)? item.card.name : "none" }}</td>'
});

new Vue({
  el: '#app',
  store,
  data: function() {
    return {
      msg: ''
    }
  },
  computed: {
    getItems() {
      return this.$store.getters.getterItems;
    }
  },
  mounted: function() {
    this.msg = JSON.stringify(this.getItems);
  },
  methods: {
    moveItem() {
      this.$store.commit('MOVE_ITEM');
      this.msg = JSON.stringify(this.getItems);
    }
  }
});
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>

<div id="app">
  <button v-on:click="moveItem">
        Move Item
      </button>

  <table cellspacing="2" border="1" cellpadding="5">
    <tr>
      <td v-for="(item, item_idx) in getItems" v-bind:key="item.col">{{ (item.card)? item.card.name : 'none' }}</td>
    </tr>
    <tr>
      <td is="player-card" v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></td>
    </tr>
  </table>
  <br/>
  <p>{{msg}}</p>
</div>

Answer №3

In addition to my query, I encountered the issue of updating arrays in vuex.

For more insights on this topic, check out "Common Beginner Gotchas"

mutations: {
MOVE_ITEM: state => {
  // Reorganize item
  state.items[0].item = state.items[2].item;
  delete state.items[2].item;

  // Simple deep array duplication
  state.items = JSON.parse(JSON.stringify(state.items));

  state.message = JSON.stringify(state.items);
}}

View the updated JSFiddle demo here

A big thank you to everyone involved.

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

Setting up and customizing Express with Angular

Currently working on a straightforward Angular/Express todo-list app, I encountered some difficulties. As the project is still in progress, after running the code on localhost:3000, I noticed that {{ thing }} was displayed literally on the webpage. The di ...

Navigating in Angular JS using $location function

I'm facing an issue with navigating between web pages using Angular JS. The first web page is index.html, followed by main.html. Additionally, there is a myscript.js file and style.css, although the latter is not relevant to this problem. My goal is t ...

Leveraging AJAX within a RESTful API in a Node.js environment to retrieve a JSON file and dynamically parse its contents according to the specific button selected on the front-end interface

Can anyone help me with understanding the communication process between server.js (Node.js) and the front-end JavaScript file? I am trying to implement AJAX as a RESTful API in the server to retrieve a JSON file, parse it based on specific button clicks in ...

Is React Context suitable for use with containers too?

React provides an explanation for the use of Context feature Context in React allows data sharing that can be seen as "global" within a tree of components, like the authenticated user, theme, or language preference. Although this concept works well for ...

Does a specific architecture exist for integrating Express with Angular using the MVC design pattern?

Looking to enhance my skills by delving into the world of Angular coupled with Express and MySQL, all within the framework of MVC architecture. There's a web app project I've been working on, available at https://github.com/NicolasMarino/Links-Ap ...

What is the best way to continuously update CSS styles within a loop?

My goal is to create a function that will change the left position of a <div> element in a loop, making it appear as though it is moving. However, instead of smoothly transitioning, the element just jumps to its end position. function animateElement ...

JavaScript function overriding

Joomla.updatebutton is a vital javascript function within the Joomla platform. It is invoked upon submitting a form when a user clicks on either the cancel or save button. I have customized this function in the following manner: saveFunction = Joomla.subm ...

Transferring mouse events from iframes to the parent document

Currently, I have a situation where my iframe is positioned over the entire HTML document. However, I am in need of finding a way to pass clicks and hover events from the iframe back to the main hosting document. Are there any potential solutions or alter ...

Unable to populate data in dropdown using Angular framework?

My datatable displays elements along with an edit button. At the top of the page, there is also an add button. The purpose of the add button is to add elements to the list, while the edit button allows for editing the data in a particular row. When the u ...

retrieving the webpage's HTML content from the specified URL using AngularJS

Utilizing the $http.get('url') method to fetch the content located at the specified 'url'. Below is the HTML code present in the 'url': <html> <head></head> <body> <pre style = "word-wrap: break ...

Wait until the link is clicked before showing the list element

Is there a way to prevent the display of list element id="two" in the code below until link "#two" has been clicked, removing element id="one"? I am looking for a CSS or JS solution that completely hides the list element rather than just hiding it from vie ...

Prevent the bootstrap dropdown menu from closing when encountering a login error during form validation using ajax and codeigniter

I encountered an issue with my dropdown menu login that utilizes bootstrap ajax and codeigniter. When I attempt to submit the form and there is an error, I have to click multiple times before the error message appears because the dropdown menu keeps closin ...

Converting Cyrillic characters to ASCII codes using JavaScript: A step-by-step guide

Is there a reliable method to convert characters from the CP1251 table to ASCII codes ranging from 0 to 255? So far, I have only come across the charCodeAt() function which is limited to codes up to 128. It returns a Unicode number for codes above that r ...

Unveil concealed information within a freshly enlarged container

As I organize my content into an FAQ format, I want users to be able to click on a link and expand the section to reveal a list of items that can also be expanded individually. My goal is to have certain list items expand automatically when the FAQ section ...

Using RegEXP in Javascript, you can easily eliminate characters that fall between two special characters without removing the special characters

I'm facing an issue with a string that looks like this: var str = "1111 type reallycoolsentence\text.json\n1111 type anotherreallycoolsentence text2.json My goal is to eliminate the characters located between the backslashes in the str ...

How to attach an event listener to an input element using Angular

I am looking to add a listener to an input element that will be triggered every time the user changes the input values. The goal is to display the current values chosen by the user. Example HTML template: <div id="idDoseLabel1" class="da ...

Transferring events and properties between a parent element

Is there a way to efficiently pass props and events down to a re-usable button component without the need to consider all possible options? For instance, if I assign a type to the <new-button> element, can it automatically pass that type on to the u ...

Vue.js is prevented by Content-Security-Policy

Running a HTML page on my node.js server with express.public() function. I included the following in my html page: <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> However, Chrome gave me a Content-Security-Pol ...

Utilize an image in place of text (script type="text/javascript")

The vendor has provided me with some code: <a class="sh_lead_button" href="https://107617.17hats.com/p#/lcf/sfrnrskrvhcncwvnrtwwvhxvzkrvzhsd" onclick="shLeadFormPopup.openForm(event)">FREE Puppies</a> <script type="text/javascript" src="htt ...

Is there a way to tell if an image has completed loading?

I am facing an issue with a block of php code that randomly loads an image. My goal is to identify when the image has finished loading so I can execute additional actions on it. This is how the image is currently being loaded: // Retrieves the image $sql ...