1

Currently I am using Vuejs2 to generate listing for image upload, which will show preview image after select an image file, here is my code written in codepan with Vuejs2: https://codepen.io/anon/pen/MELZKe

<div v-for="(image, index) in images" :key="index">
    <div class="image-upload">
        <label v-bind:for="'cover-upload-' + index">
            <img src="http://via.placeholder.com/100x100" width="100" class="preview-img"/>
        </label>
        <input v-bind:id="'cover-upload-' + index" v-bind:name="'slides[' + index + ']'" type="file" class="upload-preview" style="display:none">
    </div>
    <button type="button" 
            @click.prevent="removeImage(index)"
            v-show="image_quantity > 1">
      Remove
  </button>
</div>

I created 2 file upload images, upload first image (will preview your image), delete the first preview image, but it will delete the last preview image instead of first one.

However, almost same coding but using Vuejs1, it will delete the first preview image instead of last one. Here is codepen with Vuejs1: https://codepen.io/anon/pen/VMgqbG

I have no idea how to write such situation for Vuejs2 or I have to stick with Vuejs1?

Thanks.

Momo
  • 482
  • 5
  • 19
  • The problem I'm seeing is that the image source is not held in any variable, it's stored in the dom object in your `readURL` function, you need to move that information into your array as it's currently just a bunch of `{name=""}` elements that have no bearing on the dom. – Justin MacArthur Oct 19 '17 at 16:40
  • Also, you can use `Vue.delete(this.images, index)` in >= 2.2, there's some nifty helpers added. – Ohgodwhy Oct 19 '17 at 16:43
  • The problem is I can't bind v-model into img element as it's not input. – Momo Oct 19 '17 at 16:47
  • Vue.delete exactly same result with splice(index, 1); – Momo Oct 19 '17 at 16:49

1 Answers1

2

Using the index of an array as the key is a bad idea. This is because indexes mutate. Use a proper key and your issue is resolved.

Think about the case in the original code where there are two images in the images array. At first, the index of image one is zero and the index of the second image is one. When you delete the first image, now the index of what was originally was the second image has changed to zero, but Vue has existing DOM elements for key zero that show the image for the former object that was at index zero. Since Vue has those DOM elements for key zero, it re-uses them and it appears as though the first image was not deleted.

console.clear()
new Vue({
  el: '#content',
  data: {
    images: [{ name: '' , id: 1}],
  },
  computed: {
    image_quantity: function () {
      return this.images.length;
    },
  },
  methods: {
    removeImage: function (index) {
      this.images.splice(index, 1);
    },
    addImage: function (event) {
      event.preventDefault();
      this.images.push({
        name: '',
        id: Math.max(...this.images.map(i => i.id)) + 1
      });
    }
  }
});

function readURL(input, preview) {
  if (input.files && input.files[0] && input.files[0].type.match('image.*')) {
    var reader = new FileReader();
    reader.onload = function (e) {
      $(preview).attr('src', e.target.result);
    }
    reader.readAsDataURL(input.files[0]);
  }
}

$(document).on('change', '.upload-preview', function () {
  readURL(this, $(this).prev().find('.preview-img'));
});
<div id="content">
    <div v-for="(image, index) in images" :key="image.id">
        <div class="image-upload">
            <label v-bind:for="'cover-upload-' + index">
                <img src="https://via.placeholder.com/100x100" width="100" class="preview-img"/>
            </label>
            <input v-bind:id="'cover-upload-' + index" v-bind:name="'slides[' + index + ']'" type="file" class="upload-preview" style="display:none">
        </div>
        <button type="button" 
                @click.prevent="removeImage(index)"
                v-show="image_quantity > 1">
          Remove
      </button>
    </div>
    <button type="button" v-on:click="addImage">Create New</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
Bert
  • 80,741
  • 17
  • 199
  • 164