5

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);
     });
});

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Ah, so very close. So the issue is that, in the remove, it's not the new input that should be removed, but the previous one. The new one is empty, so that's hunky-dory. But when the remove image is clicked, I want to make sure the appropriate (now hidden) file element is removed from the page so it doesn't get sent up with the collection. That was the reasoning behind accessing it by a specific id. I'll play with this as the click event is working with your suggestion, but if you have other thoughts based on that added info, holler. Thanks!
Ok, so I got it working (in Chrome, haven't tested IE or FF) by adding a new variable to hold the parent file element, then changed 'input.remove' to be 'parentInput.remove'. Voila. Awesome, man, thanks for the help!
If I want to do the same thing like Mannish, selecting multiple files at the same time, how do I make them all appear in the browser window, each with a respective delete button?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.