12

I will advise you prior that I have limited JavaScript experience.


Currently, I have the JavaScript code:
$('#xhr-filebox').bind({
    "dragover": HandleDragEvent,
    "dragleave": HandleDragEvent,
    "drop": HandleDropEvent
});

function HandleDropEvent(e){
    var files = e.target.files || e.dataTransfer.files;
    UploadFile(files[0]);
}

(some code is omitted, but I will add more if you request)

...and the HTML:

<div class="filebox" id="xhr-filebox">
    <p id="xhr-action">...or click me to pick one.</p>
</div>

However, when I drag a file into it, the Chrome JS console says this:

Uncaught TypeError: Cannot read property 'files' of undefined

It can however get the FileList object when reading from a file input.

Curiously, when I log the event argument ( console.log(e) ), it logs it as f.event, whereas in a similar script of mine, it logs it as MouseEvent (screenshot: https://i.stack.imgur.com/3krcT.png)

Unlike the bind() function in jQuery, this uses the addEventListener() function of a DOM object returned by getElementById(), IE this is pure JavaScript. I have tried that method but nothing new happens.

svbnet
  • 1,070
  • 3
  • 11
  • 29

2 Answers2

19

If files doesn't exist on e.target, you're looking for a files on e.dataTransfer — but if there's no dataTransfer property on e (and there doesn't seem to be in your screenshot) you'll try to dereference undefined, resulting in this error.

I'd change the code to:

function HandleDropEvent(e){
    var files = e.target.files || (e.dataTransfer && e.dataTransfer.files);
    if (files) {
        UploadFile(files[0]);
    }
    else {
        // Perhaps some kind of message here
    }
}

That way, if e.target.files doesn't exist and e.dataTransfer also doesn't exist, you'll get files being undefined, rather than an error.


The event object that jQuery gives you is created and normalized by jQuery. Since we know e.dataTransfer doesn't exist on that event object (from your screenshot), my guess is that it's not one of the properties jQuery copies over from the original event object. That's okay, though, because jQuery gives us access to the original event via e.originalEvent. So I'd try:

function HandleDropEvent(e){
    var dt = e.dataTransfer || (e.originalEvent && e.originalEvent.dataTransfer);
    var files = e.target.files || (dt && dt.files);
    if (files) {
        UploadFile(files[0]);
    }
    else {
        // Perhaps some kind of message here
    }
}

That grabs files from e.target if that's where it is, or from the dataTransfer object wherever we find it (on e, or on e.originalEvent).

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I **know** the files object exists, it's just that I think that Chrome isn't passing it to the function. – svbnet May 30 '12 at 09:33
  • @Joe: My point was that your code is dereferencing `undefined`, which is why you get the error. I've added a thought: I suspect you're looking for `e.originalEvent.dataTransfer.files`. – T.J. Crowder May 30 '12 at 09:49
  • 3
    +1 `e.originalEvent.dataTransfer` is needed when using jQuery – greenimpala Dec 08 '12 at 22:01
  • 1
    I know this is late, but thanks for your solution - this saved me a bit of frustration. @T.J.Crowder – Andy Evans Mar 04 '16 at 16:14
2

I had been using the following code for the last several years:

var files = e.target.files || 
(e.dataTransfer ? e.dataTransfer.files : e.originalEvent.dataTransfer.files);

However, I've recently run into an issue using Chrome where e.target.files was there but with a length of 0 which caused files to be empty even though dataTransfer did have the dropped files.

So, I've had to use a slightly different check:

var files = e.target.files;
if (!files || files.length === 0)
    files = (e.dataTransfer ? e.dataTransfer.files : e.originalEvent.dataTransfer.files);

Hopefuly this may help someone else.

vapcguy
  • 7,097
  • 1
  • 56
  • 52
Brad Bamford
  • 3,783
  • 3
  • 22
  • 30