Daniel Luiz
Daniel Luiz

Reputation: 27

Vue.js component inside v-for is always updating the first on the list

I have a page with a component like this:

<map-itinerary v-if="region" v-for="itinerary in itineraries" :key="itinerary.hash" :itinerary="itinerary"></map-itinerary>

Inside the itinerary component I have this:

<input accept=".png" id="png" @change="fillImage" name="png" type="file">

Here's the "fillImage":

 fillImage: function(event) {
      var el = event.srcElement;
      this.imageFile = el.files[0];
      this.imageUrl = window.URL.createObjectURL(this.imageFile);

      this.enableUpload();
    }

My problem is, when I click on the input on any "itinerary" item, it always fills the data on the first "itinerary" of the list, so it always fills the image on the first item only.

How can I make it so that the component just updates itself?

Upvotes: 1

Views: 58

Answers (1)

Ferrybig
Ferrybig

Reputation: 18834

Your problem is caused because your map-itinerary component uses duplicate id's in combination with labels.

Since the input your created:

<input accept=".png" id="png" @change="fillImage" name="png" type="file">

Has the same id for every instance of map-itinerary, and the fact that it uses labels like:

<label for="png">...</label>

It means that when you interact with the label, it means that the browser thinks you mean the first component, so the vue code of the first component updates itself. This creates a confusing behaviour that the user thinks Vue updates it wrongly, while something else actually happens.

This problem should be solved inside map-itinerary, instead of using hard coded ids, it should generate dynamic ids:

computed: {
    id() {
        return 'png' + this._uid;
    }
}

and it should use that for its labels and inputs:

<input accept=".png" :id="id" @change="fillImage" name="png" type="file">
<label :for="id">...</label>

Upvotes: 1

Related Questions