0

I have vue component like this :

<template>
    <section>
        ...
    </section>
</template>
<script>
    export default {
        ...
        data() {
            return {
                allowableTypes: ['jpg', 'jpeg', 'png'],
                maximumSize: 4000000
            }
        },
        methods: {
            ...
            onFileChange(e) {
                if (this.validate(e.target.files[0])) {
                    let files = e.target.files,
                        reader = new FileReader()
                    // if any values
                    if (files.length){
                        reader.onload = (e) => {
                            this.image = e.target.result
                        }
                        reader.readAsDataURL(files[0])
                    }
                }
            },
            validate(image) {
                // validation file type  
                if (!this.allowableTypes.includes(image.name.split(".").pop().toLowerCase())) {
                    return false
                }
                // validation file size
                if (image.size > this.maximumSize) {
                    return false
                }
                // validation image resolution
                let img = new Image()
                img.src = window.URL.createObjectURL(image)
                let self = this
                img.onload = function() {
                    let width = img.naturalWidth,
                        height = img.naturalHeight

                    window.URL.revokeObjectURL(img.src)

                    if(width != 850 && height != 350) {
                        return false
                    }
                }
                return true
            }
        }
    }
</script>

If user upload image, it will call onFileChange method. Before displaying the image, it will call method validate to validate the image.

I try to validate file size and file type and it works. The problem here is validating the resolution.

From my code, it seems my code is true

But when I try like this:

I upload image with width = 100, height = 100, from the code, should it return `false``.

But when I run my code, it returns true.

Seems return is not working in the img.onload

How can I solve this problem?

grizzthedj
  • 7,131
  • 16
  • 42
  • 62
moses toh
  • 12,344
  • 71
  • 243
  • 443
  • 1
    try returning `true`within the `onload` function, i'm sure that you have a sync issue – DobleL Mar 08 '18 at 14:50
  • @DobleL I want it returning `false`. No `true` – moses toh Mar 08 '18 at 15:03
  • the problem is that it's return true because the funcion onload is async, so you need to put your return true inside the function – DobleL Mar 08 '18 at 15:14
  • @DobleL If I put return true inside the function. Where I put return false? I'm confused. Try to answer with the code – moses toh Mar 08 '18 at 15:22
  • put the return below the if condition, if the width is invalid, will return false, else will countinue executing and returning true – DobleL Mar 08 '18 at 15:25

2 Answers2

2

A nice way to handle asynchronous validation is by using Promises :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

If you are targeting Internet Explorer, make sure to use a polyfill such as this one :
https://github.com/stefanpenner/es6-promise
Your code would then look like this :

onFileChange(e) {
  let self = this
  this.validate(e.target.files[0])
    .then(function() {
      let files = e.target.files,
        reader = new FileReader()
      // if any values
      if (files.length) {
        reader.onload = (e) => {
          self.image = e.target.result
        }
        reader.readAsDataURL(files[0])
      }
    })
    .catch(function() {
      // do something in the case where the image is not valid
    })
},
validate(image) {
  let self = this
  return new Promise(function(resolve, reject) {
    // validation file type
    if (!self.allowableTypes.includes(image.name.split(".").pop().toLowerCase())) {
      reject()
    }
    // validation file size
    if (image.size > self.maximumSize) {
      reject()
    }
    // validation image resolution
    let img = new Image()
    img.src = window.URL.createObjectURL(image)
    img.onload = function() {
      let width = img.naturalWidth,
        height = img.naturalHeight

      window.URL.revokeObjectURL(img.src)

      if (width != 850 && height != 350) {
        reject()
      } else {
        resolve()
      }
    }
  })
}

If you do not want or cannot use Promises you could use a Callback to achieve the same behaviour :

onFileChange(e) {
  let self = this
  let validCallback = function() {
    let files = e.target.files,
      reader = new FileReader()
    // if any values
    if (files.length) {
      reader.onload = (e) => {
        self.image = e.target.result
      }
      reader.readAsDataURL(files[0])
    }
  }
  let unvalidCallback = function() {
    // do something in the case where the image is not valid
  }
  this.validate(e.target.files[0], validCallback, unvalidCallback)

},
validate(image, validCallback, unvalidCallback) {
  // validation file type
  if (!this.allowableTypes.includes(image.name.split(".").pop().toLowerCase())) {
    unvalidCallback()
    return
  }
  // validation file size
  if (image.size > this.maximumSize) {
    unvalidCallback()
    return
  }
  // validation image resolution
  let img = new Image()
  img.src = window.URL.createObjectURL(image)
  let self = this
  img.onload = function() {
    let width = img.naturalWidth,
      height = img.naturalHeight

    window.URL.revokeObjectURL(img.src)

    if (width != 850 && height != 350) {
      unvalidCallback()
      return
    } else {
      validCallback()
    }
  }
}
Guillaume Meral
  • 452
  • 2
  • 8
0

It's onloadend not onload.

Change your code to this:

let self = this;     

var reader = new FileReader(); 
reader.onloadend = () => {
 // you logic here (use self, not this)
}
samayo
  • 16,163
  • 12
  • 91
  • 106
  • It does not work. Try to answer by my code. My code use `let img = new Image()`. No `var reader = new FileReader(); `. I using it, because I want to get width and height of image – moses toh Mar 08 '18 at 15:05