Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple File Upload with jQuery

I am trying to allow multiple file uploads prior to a form post. What I'd like is for the user to only ever see one file upload element, and each time a file is selected, show a new <li> that contains the filename and an image/link to remove that specific file from the collection. There's a jQuery MultiFile plugin that does what I want, but I can't get the custom styling to work the way I want so I'm rolling my own.

So far I have the below code. It successfully adds the <li>, hides the file upload element with the newly selected file, and appends an empty file upload element to the page for the user to select a new file. I'm struggling to appropriately manage the removal of elements and, while it's not that difficult, I've been staring at this long enough that now it just feels like I'm doing it all wrong. I'm hoping others might have some insight, tips to clean this up (i.e. make it more elegant), and such. Code below.

HTML:

<div id="product-image-area" class="group" style="border-bottom: none; padding-top: 0"> 
    <ul id="photos" class="nobull">    
     <li id="no-product-images-msg" class="" > 
            <%= Html.Image("no-photos.png") %> 
     </li> 
   </ul>
 </div> 
 <div id="upload-area"> 
    <h4 class="st">Upload an image</h4>
    <p class="note">Allowed file types are .gif, .jpg, .jpeg, and .png</p> 
    <p id="file-input" class="st sb"><input class="photo-upload" id="VenuePhotos_0" name="VenuePhotos[]" type="file" /></p> 
 </div>

Script:

$(function () {
     $('.photo-upload').live('change', function () {
         var fileCount = new Number($(this).parent().children('.photo-upload').length);
         $('#photos').append('<li id="venue_photo_' + (fileCount - 1) + '">' + $(this).val() + '<img title="' + (fileCount - 1) + '" src="/vh/public/images/icon-delete.png" class="delete"  /></li>');
         $(this).parent().append(
             $(this).clone().attr('id', 'VenuePhotos_' + fileCount)
         );
         $(this).hide();
     });
     $('.delete').live('click', function (e) {
         var index = $(e).attr('title');
         $('#file-input').children('.photo-upload').remove('#VenuePhotos_' + index);
         $('#photos').children().remove('#venue_photo_' + index);
     });
});
like image 477
nkirkes Avatar asked Oct 13 '22 20:10

nkirkes


1 Answers

The answer is the closure, one of the most powerful features of JavaScript. Functions that are inside others are able to access the variables of the enclosing functions.

You could bind your delete function when a file input is added instead of using .live and dynamically generated ID's:

$('.photo-upload').live('change', function () {
     var li = $('<li />').text($(this).val()),
         img = $('<img src="/vh/public/images/icon-delete.png" class="delete" />'),
         input = $(this).clone();

     li.append(img);
     $('#photos').append(li);
     $(this).parent().append(input);
     $(this).hide();

     img.click(function() {
         input.remove();
         li.remove();
     });
 });

In this example, the click handler for the delete button accesses the jQuery wrappers (for the two elements that must be removed) that were obtained in the parent function.

like image 161
PleaseStand Avatar answered Nov 02 '22 13:11

PleaseStand