vue.js @emit is not picked up by parent

70 Views Asked by At

In my app I have a form, in the ManageCards component, that conatins a child component ImageUpload, that emits and imagefile and its local URL to the parent:

<form  class="mb-3" > 
  <div class="form-group">
    <h4>{{card.description}}</h4>
    <textarea  class="form-control" :placeholder="card.description" v-model="card.description" />
  </div>
  <div>
    <img  v-if="card.picture" class="img-circle" style="width:150px"  v-bind:src="card.picture" />
  </div>
  <div id="preview">
    <h4>Preview</h4>
    <ImageUpload  :imgUrl="url" @newPicture="updatePicture"></ImageUpload> 
    <button @click="addCard" type="button" class="btn btn-primary btn-block" style="color:white">Save</button>
  </div>
</form>

De addCard method calls a POST command to send information to the API:

addCard() {
  const formData = new FormData();
  formData.append('title',this.card.title);
  formData.append('description',this.card.description);
  formData.append('imagefile',this.selectedFile);
  formData.append('game_id',this.currentGame.id);
  // ...
}

SelectedFile and card.picture should be populated by the emitted method updatePicture:

updatePicture(imageData) {
  console.log("emit ontvangen");
  this.selectedFile = imageData.file;
  this.card.picture = imageData.picture;
  // ...
}

The ImageUpload Component itself looks like:

<template>
  <div class="Image-Upload-wrapper Image-upload"> 
    <div>
      <input type="file" v-on:change="onFileChange" ref="fileUpload" id="file_picture_input" />
      <label for="file_picture_input" class="upload_picture_button">Kies afbeelding</label>
    </div>
    <div id="croppie"></div>     
    <div class="upload-wrapper">
      <button type="button" class="btn btn-primary btn-sm" v-on:click="setImage">
        <!-- type="button"" anders vervest de knop de hele pagina " -->
        Set image   
      </button>
    </div>   
  </div>
</template>

<script>
// uitleg over Croppie::https://www.youtube.com/watch?v=kvNozA8M1HM
import Croppie from 'croppie';

export default {
  props: [
    'imgUrl'
  ],
  mounted() {
    this.setUpCroppie()
  },
  data() {
    return {
      croppie: null,
      croppieImage: '',
      selectedFile: '',
      picture: '',
      url: '',
    }
  },
  methods: {
    setUpCroppie() {
      let el = document.getElementById('croppie');
      this.croppie = new Croppie(el, {
        viewport: { width: 200, height:200, type:'circle' },
        boundary: { width: 220, height:220 },
        showZoomer: true,
        enableOrientation: true
      });
      this.croppie.bind({       
        url: this.url
      });
    },
    setImage() {
      this.croppie.result({
        type: 'canvas',
        size: 'viewport'
      })
      .then(blob =>fetch(blob))
      .then(res => res.arrayBuffer)
      .then(buf => new File([buf], this.croppieImage.name, { type:'image/png' }))
      .then(file => { 
        this.croppieImage = file;
        this.picture = URL.createObjectURL(this.croppieImage);
        const imageData = {
          picture: this.picture, 
          file: this.croppieImage
        };
        console.log("klaar voor emit...?");
        this.$emit('newPicture', imageData);
        this.url = '';
      })
    },
    onFileChange(e) { 
      if (e.target.files && e.target.files.length > 0) {
        this.selectedFile = e.target.files[0];
        console.log("gekozen file is: " + this.selectedFile.name);
        this.url = URL.createObjectURL(this.selectedFile);
        this.croppie.bind({
          url: this.url
        });
      } else {
        // Geen afbeelding geselecteerd, instellen op een standaardwaarde (bijv. een lege string)
        this.selectedFile = null;
        this.url = '';
      }
    } 
  },
}
</script>

In the Console I do see: klaar voor emit...?, from the setImage method in the chold component. I do not see the emit ontvangen from the emit method in the parent. Consequently the required fields for the POST command are also not populated.

Can anyone see what (probably silly) mistake I am making?

1

There are 1 best solutions below

5
rozsazoltan On

Child Element

A child element needs to declare the emits.

Options API
export default {
  emits: ['first-emit-name', 'second-emit-name'],
}
Composition API
const emit = defineEmits(['first-emit-name', 'second-emit-name'])

After this, it will forward the declared emits to the parent element in Vue.

Options API
this.$emit('first-emit-name')
this.$emit('second-emit-name')
Composition API
// After const emit declaration
emit('first-emit-name')
emit('second-emit-name')

Parent Element

<ChildElement @first-emit-name="(e) => ..." @second-emit-name="(e) => ...">