musicformellons
musicformellons

Reputation: 13413

Vue child component property does not work

I am trying to break this code [A] (see fiddle at bottom):

  <div class="q-uploader-files scroll">
      <q-item
        v-for="file in files"
        :key="file.name"
      >
        <q-progress :percentage="file.__progress"/>
        <div>
          {{ file.__progress }}%
        </div>

        <q-item-side v-if="file.__img" :image="file.__img.src">
        </q-item-side>
        <q-item-side right>
          <q-item-tile
            :icon="file.__doneUploading ? 'mdi-done' : 'mdi-clear'"
            :color="file.__doneUploading ? 'primary' : 'color'"
            @click.native="__remove(file)"></q-item-tile>
        </q-item-side>
      </q-item>
    </div>

into [B] the basically the same code but then with a child component. Here the parent:

<div class="q-uploader-files scroll">
  <my-uploader-progress
    v-for="file in files"
    :file="file"
    :key="file.name"
    :color='color'
  >
  </my-uploader-progress>
</div>

And here the child:

<template>
  <q-item>
    <q-progress
      :color="file.__failed ? 'negative' : 'grey'"
      :percentage="file.__progress"
    />
    <div>
      {{ file.__progress }}%
    </div>

    <q-item-side v-if="file.__img" :image="file.__img.src"/>
    <q-item-side v-else icon="mdi-file" :color="color"/>
    <q-item-main :label="file.name" :sublabel="file.__size"/>

    <q-item-side right>
      <q-item-tile
        :icon="file.__doneUploading ? 'mdi-done' : 'mdi-clear'"
        :color="file.__doneUploading ? 'primary' : 'color'"
        @click.native="__remove(file)"
      />
    </q-item-side>
  </q-item>
</template>

On the child I have set the file property:

  props: {
    file: {
      type: File,
      required: true
    }
  },

Somehow in the parent-child code there must be a problem as the file __img property does not exist in the child (at render) in [B] see:

enter image description here

, whereas it does exist in [A]:

enter image description here

What's wrong? There are no errors in the console.

The original ([A]) code is from here. The File Object consists of a xhr instance (I suppose?!).

Here fiddles/ sandboxes for [A] and for [B]. Press ADD and select an image to upload, it will not upload but [A] will show its thumbnail img etc; do the same for [B] and these will not show.

NOTA BENE: I noticed that the file.__img does not show first in [B], but when I start editing code in the child component..., it suddenly SHOWS. So apparently/ maybe it is something asynchronous and after a render-refresh it is there...?!

Upvotes: 8

Views: 2482

Answers (4)

Husam Elbashir
Husam Elbashir

Reputation: 7187

If you're looking for a working solution you can simply assign a key to the my-uploader-progress component based on the presence of an __img property, which will force it to re-render when the property becomes available ..

<my-uploader-progress
        v-for="file in files"
        :file="file"
        :key="file.__img ? '1-' + file.name : '0-' + file.name"
        :hide-upload-progress="hideUploadProgress"
        :color='color'
>
</my-uploader-progress>

CodeSandbox

Upvotes: 5

Marc
Marc

Reputation: 5465

You have to make the property value reactive by returning a factory function.

props: {
  file: {
    type: File,
    required: true,
    default: function () {
        return {
          name: '',
          _progress: 0
        }
      }
  }
},

Upvotes: 5

Gerson E. Aguirre
Gerson E. Aguirre

Reputation: 875

If you are updating the property value of an object in props after the child has been mounted it wont work, you would have to replace the complete object to make it work,

Upvotes: 4

waleed ali
waleed ali

Reputation: 1195

Sort of an ugly hack, but I hope this will fix the issue. Try setting a timeout in the mounted function to buy some time before the file gets loaded and then true the v-if condition to load image element in the DOM.

<template>
  <q-item-side v-if="file_loaded" :image="file.__img.src"/>
</template>

<script>
data () {
  file_loaded: false
},
mounted() {
  setTimeout(() => {
    this.file_loaded = true
  }, 1000)
}
</script>

I have tried this in your sandbox [B] and it's working fine.

enter image description here

Upvotes: 4

Related Questions