Vue's dynamic component list now accurately removes incorrect HTML nodes

Exploring the capabilities of Vue.JS by creating components dynamically and composing them together.

Encountered an unusual issue where, even though data seems to be updating correctly, removing one of the boxes using splice() always results in the removal of the last item in the rendered HTML.

Take a look at this example fiddle. Testing was done on Chrome.

https://jsfiddle.net/afz6jjn0/

For reference, here's the Vue component code:

Vue.component('content-longtext', {
  template: '#content-longtext',
  props: {
    model: { type: String, required: true },
    update: { type: Function, required: true }
  },
  data() {
    return {
      inputData: this.model
    }
  },
  methods: {
    updateContent(event) {
      this.update(event.target.value)
    }
  },
})

Vue.component('content-image', {
  template: '#content-image',
})

Vue.component('content-list', {
  template: '#content-list-template',
  props: {
    remove: { type: Function, required: true },
    update: { type: Function, required: true },
    views: { type: Array, required: true }
  },
  methods: {
    removeContent(index) {
      this.remove(index)
    },
    updateContent(index) {
      return (content) => this.update(index, content)
    },
  },
})

Vue.component('content-editor', {
  template: '#content-editor',
  data() {
    return {
      views: [
        {type: 'content-longtext', model: 'test1'},
        {type: 'content-longtext', model: 'test2'},
        {type: 'content-longtext', model: 'test3'},
        {type: 'content-longtext', model: 'test4'},
        {type: 'content-longtext', model: 'test5'},
      ],
    }
  },
  methods: {
    newContentBlock(type) {
      this.views.push({type: 'content-longtext', model: ''})
    },
    updateContentBlock(index, model) {
      this.views[index].model = model
    },
    removeContentBlock(index) {
      this.views.splice(index, 1)
    },
  },
})

let app = new Vue({
  el: '#app'
})

Answer №1

Thanks to the helpful documentation, I was able to resolve the issue I was facing.

The main point is that if you do not already have a unique key, you should store the array index of the object within the object itself. This is important because when you modify the source array, you are also modifying its keys. Vue may consider the last item as missing rather than the removed item.

views: [
  {index: 0, type: 'content-longtext', model: 'test1'},
  {index: 1, type: 'content-longtext', model: 'test2'},
  {index: 2, type: 'content-longtext', model: 'test3'},
  {index: 3, type: 'content-longtext', model: 'test4'},
  {index: 4, type: 'content-longtext', model: 'test5'},
],

...

newContentBlock(type) {
  this.views.push({index: this.views.length, type: 'content-longtext', model: ''})
},

Once you have stored the array index, remember to add the :key binding to the iterator in the template and bind that stored value.

<div v-for="(currentView, index) in views" :key="currentView.index">
  <component :is="currentView.type" :model="currentView.model" :update="updateContent(index)"></component>
  <a v-on:click="removeContent(index)">Remove</a>
</div>

Lastly, ensure that you maintain the integrity of your indexes when making changes to the array.

removeContentBlock(index) {
  this.views
    .splice(index, 1)
    .map((view, index) => view.index = index)
},

https://jsfiddle.net/afz6jjn0/5/

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

Loading input field values dynamically in Bootstrap modal

In my Laravel application, I have a Bootstrap modal that I want to populate dynamically with data from the database. The goal is to update the values of the input fields in the modal. I have made progress on this front... Here is what I have in my view fi ...

Vue 3 TypeScript Error 2339: The attribute xxx is not present in the type {

My tech stack includes Vue3 with TypeScript, axios, and sequelize. Currently, I am working on a form that contains just one textarea for users to post on a wall. Below is the script I have written in my form component: <template> <div id="P ...

Promise.all does not pause for a new Promise to finish resolving

This particular section belongs to a spa utilizing nodejs and jquery. The getToday function is supposed to console log "result:", leading to the entire output being 1, followed by result:, and finally 2. However, it seems that the code does not wait for ge ...

Generating a JavaScript object from a string to optimize its compatibility with datatables

This inquiry pertains to the plugin available at: var hidecols = '{"sClass": "Hide", "aTargets": [0]},{"sClass": "asdf", "aTargets": [1]},{"sClass": "qwer", "aTargets": [2]}'; var hidecolsobj = eval('(' + hidecols + ')'); ...

Instance of a Component Available Worldwide

When working with Vue 2.x in our production applications, we utilize a toast component. This toast component is mounted once through a plugin (code provided below) and then added to the Vue prototype for easy access in every component instance. This setup ...

The data in AngularJS is not being successfully incorporated into the service

Utilizing angularjs and ajax, I am attempting to retrieve data from a webservice and pass it to the controller. To accomplish this, I am using a holder (a factory method or service). The setup works fine without the webservice, but when trying to fetch dat ...

javascript onload select the text in the textarea

Is there a way to have JavaScript automatically highlight the text inside a textarea when the page is loaded? ...

jQuery Soundboard - Pressing a single button will automatically deactivate all other buttons

I am currently developing a unique jQuery/PHP soundboard feature where I am faced with the challenge of stopping the HTML5 Audio playback when clicking on just one button, while attached to several other buttons. Here is what I have managed to code so far: ...

Align a collection of images in a grid format on the center of the page with

I am trying to center a div that contains multiple 145px X 145px thumbnail images without setting a fixed width. The goal is to have as many images in each row as the browser window can fit. However, I want to keep the images left-aligned within the center ...

Adding Options on the Fly

I am struggling with integrating option elements into optgroups within my HTML structure using JavaScript, particularly while utilizing the jQuery Mobile framework. Below is the initial HTML setup: <form> <div class="ui-field-contain"> ...

I encountered an issue while using the tab bar feature in Bootstrap where I wasn't able to navigate back to the first tab or any

My current project involves JavaScript, and I integrated a Bootstrap tab bar component. However, when I try to run the code in Google Chrome, I encounter an issue. The first time I select the first tab, the content displays correctly. But when I select the ...

Is it a scope issue if ng-click is not firing and the function is not working properly?

I'm facing an issue with an animation that is not working as intended. The goal is to have the search button trigger an animation to pull a search bar from the right side, allowing users to input their search query. However, the ng-click function does ...

Utilizing Node.js ORM2 callback functions with custom parameters

Currently, I am developing models using a for loop: for (var j = 0; j < data.length; j++) { models.MyModel1.create({ name : data[j].name }, function(err, model){ if (err) { throw err } ...

Most effective method for adding JQuery events to dynamically generated buttons

I am dynamically generating Twitter Bootstrap modals based on user actions (Long Story). Sometimes, the user may see up to 100 modals on their screen. Each modal contains 5 dynamic buttons, each serving a different purpose with unique ids. I am using jQue ...

JavaScript Money Exchange

Can currency be recalculated using JavaScript or jQuery? For instance: <div id="price">$99.00</div> Could become <div class="gbp" id="price">£63.85</div> If a class of "GBP" was added to the div tag? ...

Problem with Jquery Sticky Navigation

I've been struggling to understand this issue and can't seem to find any help. http://fiddle.jshell.net/DQgkE/7/show/ The user experience is currently a bit glitchy, but what I would like is: 1) When scrolling down the page, I want the Sticky ...

I am having trouble retrieving images on my website and displaying URL images

Every time I attempt to retrieve an image URL from the database for the client, I encounter the following error: Refused to load the image 'https://nuclear-photos.s3-ap-southeast-1.amazonaws.com/…22:33:44%20GMT+0400%20(GST)TEST.png' because i ...

The function 'find' cannot be invoked on an undefined object

I'm currently working on implementing objects in my jQuery code. So far, I have the following: var options = { ul: $(this).find('.carousel'), li: options.ul.find('li') } The li property is causing an error - Cannot call meth ...

Is it possible for node modules to access and utilize protractor parameters?

Is it feasible for a node module to access a protractor parameter? I am in need of defining a parameter in my protractor conf.js file and then running a specific section of the shared node module js file across 5 projects. For instance, in my conf.js: ...

Dispensing guarantees with Protractor

q library offers a unique feature that allows resolving and spreading multiple promises into separate arguments: If you have a promise for an array, you can utilize spread instead of then. The spread function distributes the values as arguments in the f ...