1

I have form with the following form:

<form>
    ...
    <input type="file" multiple="multiple" id="images" />
    <a id="add">Add</a>
    ...
    <input type="submit" value="Submit" />
</form>

The add element's click event is then wired up like so:

var images = [];

$("#add").click(function() {
    var files = $("#images")[0].files;

    for (var i = 0; i < files.length; i++) {
        images.push[files[i];
    }

    $("#images").val("");
});

This allows me to add the images from multiple locations. Now I need to send the files back to the server. I found the following question:

Passing path to uploaded file from HTML5 drag & drop to input field

Which seems to be similar. Therefore I used the following to wire up an event when the form is submitted:

var form = $("form");

form.submit(function() {
    for (var i = 0; i < images.length; i++) {
        var reader = new FileReader();

        reader.onload = function(e) {
            $("<input>").attr({ type: "hidden", name: "images[]" }).val(e.target.result).appendTo(form);
        };

        reader.readAsDataURL(images[i]);
    }
});

Finally on the server I have the following code:

print_r($_POST);
print_r($_FILES);

However neither collection contains an item for the images submitted. I was wondering what I am doing wrong? Thanks

Community
  • 1
  • 1
nfplee
  • 7,643
  • 12
  • 63
  • 124
  • Do you have multiple items with the same id? If so, you'll need to change that. Duplicate id's are not allowed in HTML pages. – Jay Blanchard Feb 09 '15 at 16:55
  • No I only have the one element named images. Also I have tested this with different names but nothing seems to work. – nfplee Feb 09 '15 at 16:57
  • Any errors in the console? For instance this line `images.push[files[i];` is bad. – Jay Blanchard Feb 09 '15 at 16:58
  • It doesn't look like you're actually reading any files with those FileReader objects you're creating, so your onload event which is appending the input elements to the form may actually not be firing. – Aaron Feb 09 '15 at 16:59
  • Nope, no javascript errors. I also stepped through it with the developer tools and correctly executes the onload event for each image added when the form submits. – nfplee Feb 09 '15 at 17:00
  • @Aaron I missed a line in my question when copying it across (good spot). Unfortunately it doesn't help solve the problem. – nfplee Feb 09 '15 at 17:04
  • Ahh, ok. So on the server side, you're *not* seeing an array of data urls in $_POST['images'], correct? – Aaron Feb 09 '15 at 17:34

1 Answers1

0

Alright, I think your problem here is being caused by the FileReader's load event handler, which appends those data URLs to the form, being called after the form is submitted to the server.

You could solve this problem, and do away with the superfluous images variable and submit event handler by adding these items to the form in the click handler for the Add link. You can also use this opportunity to do a little client side validation, preventing duplicate data URLs from being uploaded to the server, and even to add a preview/remove option for the selected images.

Furthermore, you could do away with the Add link by replacing its click handler with a change handler attached to your file input.

Edit (nfplee):

var images = [];

$("#add").click(function() {
    var files = $("#images")[0].files;

    for (var i = 0; i < files.length; i++) {
        var reader = new FileReader();

        reader.onload = (function(file) {
            return function(e) {
                images.push({ name: file.name, file: e.target.result });
            };
        })(files[i]);

        reader.readAsDataURL(files[i]);
    }

    $("#images").val("");
});

var form = $("form");

form.submit(function() {
    for (var i = 0; i < images.length; i++) {
        $("<input>").attr({ type: "hidden",
            name: "images[" + i + "][name]" }).val(images[i].name).appendTo(form);
        $("<input>").attr({ type: "hidden",
            name: "images[" + i + "][file]" }).val(images[i].file).appendTo(form);
    }
});
nfplee
  • 7,643
  • 12
  • 63
  • 124
Aaron
  • 5,137
  • 1
  • 18
  • 20
  • Thanks @Aaraon. Your answer helped point me in the right direction. I'm not sure if you were entirely correct but I found by moving the FileReader's load event to either the images change or the add click event handlers worked fine. I'm guessing the FileReader doesn't work when the form is submitted. However it looks cleaner now anyway. The reason for the images collection was that I actually use a javascript template engine to observe the collection and update the ui as it's updated. I'll edit your answer with the final code. – nfplee Feb 10 '15 at 10:13
  • Excellent! I'm glad you got it working. FWIW, I think the issue with the initial approach had more to do with the order in which JavaScript schedules events and executes their handlers than it did with the `FileReader` object itself. Those `load` events you were listening for were being added to the event queue *after* the `submit` event in which the listeners were bound to those `FileReader`s. For anyone interested, a handy refresher on JavaScript's event timing is available at http://javascript.info/tutorial/events-and-timing-depth. – Aaron Feb 11 '15 at 16:22