Gadgetster
Gadgetster

Reputation: 483

Clear an image preview file that was removed from the array with jquery

I tried to figure this out for over a month now. I cannot get the image to be removed from the array once the image was clicked on 'x' on the previewer.

http://jsfiddle.net/ERZVC/2/

My attempt to use splice failed!

$('#list').on('click', '.remove_img_preview',function () {
        $(this).parent('span').remove();

        //this is not working...
        var i = array.indexOf($(this));
        if(i != -1) {
            array.splice(i, 1);
        }
        // tried this too:
        //$(this).parent('span').splice( 1, 1 );

        count--;
    });

please help me out!

EDIT:

The reason I need it removed from the array or the input file list is because when submitting the form, it should only upload the images that are in the previewer and not the ones that were removed from it.

Example: If I upload image1, image2, image3, then remove image2, it should only upload image1 and image3 on submission.

Upvotes: 4

Views: 4478

Answers (2)

tftd
tftd

Reputation: 17062

From what I understand in your question, you're trying to remove a file from a multifile input form. Unfortunately this is not possible due to security restrictions in all browsers. The multifile input returns a read-only FileList, which contains a collection of File objects. Therefore you can't simply remove an element from the list. (Checkout this question.)

There is a workaround, though, which requires AJAX for handling the form. You can process the FileList and store the files in an array. Then attach an on('submit') function which will intercept the submit action. Instead of a submit event, an $.ajax() request, sending the serialized form will be made.

Example:

<!-- upload.html -->
<!DOCTYPE html>
<html>
<head lang="en">
    <title>Upload</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

    <script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
    <script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>

    <style type="text/css">
        ul{
            width: 650px;
        }
        ul li {
            list-style: none;
            width: 165px;
            float:left;
            position: relative;
            margin: 0px 0px 0px 20px;
        }

        .thumb {
            width: 150px;
        }

        .remove {
            position: absolute;
            top: 0px;
            right: 0px;
            color: red;
            cursor: pointer;
        }

        /* Prettify json output.. not needed in your code */
        pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
        .string { color: green; }
        .number { color: darkorange; }
        .boolean { color: blue; }
        .null { color: magenta; }
        .key { color: red; }

    </style>

    <script type="text/javascript">
        $(document).ready(function() {
            // You don't need this - it's used only for the demo.
            function jsonPrettify(json) {
                if (typeof json != 'string') {
                    json = JSON.stringify(json, undefined, 2);
                }
                json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
                return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
                    var cls = 'number';
                    if (/^"/.test(match)) {
                        if (/:$/.test(match)) {
                            cls = 'key';
                        } else {
                            cls = 'string';
                        }
                    } else if (/true|false/.test(match)) {
                        cls = 'boolean';
                    } else if (/null/.test(match)) {
                        cls = 'null';
                    }
                    return '<span class="' + cls + '">' + match + '</span>';
                });
            }
            // You don't need this - it's used only for the demo.



            // The code
            var filesArray = [];

            /**
             * This function processes all selected files
             *
             * @param e eventObject
             */
            function previewFiles( e ) {
                // FileList object
                var files = e.target.files;
                var preview = $('#imagePreviews');

                // Loop through the FileList and render image files as thumbnails.
                for (var i = 0, f; f = files[i]; i++) {

                    // Only process image files.
                    if (!f.type.match('image.*')) {
                        continue;
                    }

                    var reader = new FileReader();

                    // Closure to capture the file information.
                    reader.onload = (function(theFile) {
                        return function(e) {
                            // Render thumbnail.
                            var li = $('<li><img class="thumb" src="'+ e.target.result +'" title="'+ escape(theFile.name) +'"/><div class="remove">X</div></li>');
                            preview.append(li);

                            // Append image to array
                            filesArray.push(theFile);
                        };
                    })(f,preview);

                    // Read the image file as a data URL.
                    reader.readAsDataURL(f);
                }
            }
            // Attach on change to the file input
            $('#fileInput').on('change', previewFiles);

            /**
             * Remove the file from the array list.
             *
             * @param index integer
             */
            function removeFile( index ){
                filesArray.splice(index, 1);
            }
            // Attach on click listener which will handle the removing of images.
            $(document).on('click', '#imagePreviews .remove',function(e){
                var image = $(this).closest('li');

                console.log(image.index());

                // Remove the image from the array by getting it's index.
                // NOTE: The order of the filesArray will be the same as you see it displayed, therefore
                //       you simply need to get the file's index to "know" which item from the array to delete.
                console.log('Files:' ,filesArray);
                removeFile(image.index());
                console.log('Files:' ,filesArray);

                // Fadeout the image and remove it from the UI.
                image.fadeOut(function(){
                    $(this).remove();
                });
            });


            /**
             * This function processes the submission of the form.
             *
             * @param e
             */
            function submitForm(e){
                // Stop the form from actually submitting.
                e.preventDefault();

                // Create a new FormData based on our current form.
                // Makes live easier as we can attach a list of File objects.
                var formData = new FormData($('#myForm')[0]);
                for(var i= 0, file; file = filesArray[i]; i++){
                    formData.append('files[]', file);
                }

                // Send the ajax request.
                $.ajax({
                    url: 'upload.php',
                    type: 'POST',
                    data: formData,
                    processData: false,
                    contentType: false,
                    success: function(response) {
                        $('#response').html(jsonPrettify(response));
                    }
                });
            }
            // Attach on submit to the form submission.
            $('#myForm').on('submit', submitForm);
        });
    </script>

</head>

<body>

    <div style="width: 650px; border: 1px #D8D8D8;">

        <form id="myForm" action="upload.php" method="post" enctype="multipart/form-data">
            <label>Name</label>
            <input type="text" name="firstName" value="FirstName"/>
            <input type="text" name="lastName" value="LastName"/>

            <!-- Don't set a name of this input so that we won't need to remove it before serialization. -->
            <input id="fileInput" type="file" value="Upload button" multiple/>

            <div style="width: 600px; border: 1px solid #D8D8D8;">
                <ul style="list-style: none;" id="imagePreviews">
                </ul>

                <div style="clear: both;">&nbsp;</div>
            </div>

            <br>

            <input type="submit"/>

        </form>

        <br>
        Upload.php response<br>
        <pre id="response" style="width: 650px;"></pre>
    </div>

</body>
</html>

// upload.php
<?php

header('Content-Type: application/json');
echo json_encode(array('success' => true, '$_FILES' => $_FILES, '$_POST' => $_POST));

?>

Hope this helps.

Upvotes: 4

Roko C. Buljan
Roko C. Buljan

Reputation: 206689

jsBin demo

var $fileUpload = $("#files"),
    $list = $('#list'),
    thumbsArray = [],
    maxUpload = 5;

// READ FILE + CREATE IMAGE
function read( f ) {
  return function( e ) {
    var base64 =  e.target.result;
    var $img = $('<img/>', {
      src: base64,
      title: encodeURIComponent(f.name), //( escape() is deprecated! )
      "class": "thumb"
    });
    var $thumbParent = $("<span/>",{html:$img, "class":"thumbParent"}).append('<span class="remove_thumb"/>');
    thumbsArray.push(base64); // Push base64 image into array or whatever.
    $list.append(  $thumbParent  );
  };
}

// HANDLE FILE/S UPLOAD
function handleFileSelect( e ) {
    e.preventDefault(); // Needed?
    var files = e.target.files;
    var len = files.length;
    if(len>maxUpload || thumbsArray.length >= maxUpload){
      return alert("Sorry you can upload only 5 images");
    }
    for (var i=0; i<len; i++) { 
        var f = files[i];
        if (!f.type.match('image.*')) continue; // Only images allowed      
        var reader = new FileReader();
        reader.onload = read(f); // Call read() function
        reader.readAsDataURL(f);
    }
} 

$fileUpload.change(function( e ) {
    handleFileSelect(e);
});

$list.on('click', '.remove_thumb', function () {
    var $removeBtns = $('.remove_thumb'); // Get all of them in collection
    var idx = $removeBtns.index(this);   // Exact Index-from-collection
    $(this).closest('span.thumbParent').remove(); // Remove tumbnail parent
    thumbsArray.splice(idx, 1); // Remove from array
}); 

To explain the pain above:

the thumbnails created by the above code look like:

<span class="thumbParent">
    <img class="thumb" src="base64string....">
    <span class="remove_thumb"></span>
</span>

now, clicking the remove thumbnail Button we need to get a collection of those buttons in order to create an index variable (that will later .splice() our images array) by doing: $removeBtns.index(this).

I know I edited a bit the classNames, feel free to undo if you want.

Upvotes: 1

Related Questions