0

I am using replaceWith for input type=file to handle changes of the file the user wants to upload.

I have this code:

$('#add_cv_input').change(function() {
    // here is some code               
    else {
        alert('put one of this: pdf doc docx');
        $("#add_cv_input").replaceWith('<input id="add_cv_input" type="file"/>');
    }
});

now the problem is that this jquery changed event does not being called after the first time that the user had uploaded the wrong extension.

I don't have a clue why this is happening. Everything works fine if at the first time the user uploads a valid extension and then he changes it to other valid extension.

David G
  • 94,763
  • 41
  • 167
  • 253
vlio20
  • 8,955
  • 18
  • 95
  • 180

2 Answers2

4

When you destroy the first item, the event handler is destroyed with it. If you want the event handler to be on the new item, you have two options:

  1. You can reinstall the event handler on the new object after creating it.
  2. You can use delegated event handling from a parent that is not destroyed.

It's probably easiest to use delegated event handling with the dynamic form of .on():

$(some parent selector).on('change', '#add_cv_input', function() {
    // code here
});

Where you pick some parent selector that is as close as possible to #add_cv_input, but is not destroyed.


If you wanted to reattach the event handler after replacing the element, you could do so like this (though delegated event handling would be cleaner):

function processChange() {
    // here is some code               
    else {
        alert('put one of this: pdf doc docx');
        $("#add_cv_input").replaceWith('<input id="add_cv_input" type="file"/>');
        $('#add_cv_input').change(processChange);
    }
});

$('#add_cv_input').change(processChange);
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • How do I reinstall the event after destroying the element? – vlio20 Oct 14 '12 at 07:04
  • @VladIoffe - I added how to reinstall to my answer. – jfriend00 Oct 14 '12 at 07:20
  • are you sure it is like this: $('#add_cv_input').change(processChange); and not like this: $('#add_cv_input').change(processChange());? – vlio20 Oct 14 '12 at 07:58
  • after changing it to $('#add_cv_input').change(processChange()); it is not working on opera, works fine on chrome and ie, any idea why? – vlio20 Oct 14 '12 at 08:09
  • @VladIoffe - I'm quite sure it's NOT `$('#add_cv_input').change(processChange())`. That just calls `processChange()` immediately and passes it's return value to the `.change()` method. That is not what you want. `.change()` takes a function reference. You'd have to suppply a working example (perhaps in a jsFiddle) that we could debug in Opera to know more about that. The code is technically correct. – jfriend00 Oct 14 '12 at 15:25
3

You are destroying the original element which the event handler was bound to, which is why its not triggered again. Instead of replacing the element try to reset it.

Edit: Seeing as resetting the single file input is non-trivial(as this.value = null; doesn't work in all browsers), replacing the element seems to be the better option.

You can just attach the event handler to the the newly created element. [.replaceAll()]

function cv_input_file(){
    // here is some code               
    else {
        alert('put one of this: pdf doc docx');
        $('<input id="add_cv_input" type="file"/>')
         .replaceAll("#add_cv_input")
         .change(cv_input_file);
    }
}
$('#add_cv_input').change(cv_input_file);

or use event delegation so you wouldn't have to add a handler every time you replace the element.

$(document/*or the closest static ancestor*/).on('change', '#add_cv_input', function() {
    // here is some code               
    else {
        alert('put one of this: pdf doc docx');
        $("#add_cv_input").replaceWith('<input id="add_cv_input" type="file"/>');
    }
});
Musa
  • 96,336
  • 17
  • 118
  • 137
  • +1 This is a more feasible solution as all other information of the element does not need to be reapplied. – pimvdb Oct 13 '12 at 21:38
  • I don't want to reset all of the form, I want to rest only the input type=file element. How do I do that? – vlio20 Oct 13 '12 at 21:52
  • @VladIoffe try using `this.value = null;` instead of the replacement statement. – Musa Oct 13 '12 at 22:23
  • I will thanks, but is it changing also the file in the element and not only the path? – vlio20 Oct 13 '12 at 22:25
  • @VladIoffe I just tested it an dit doesn't work in IE or Opera, I guess replacing the element then re-attaching the event handler is the better option. See http://jsfiddle.net/etZcv/ – Musa Oct 13 '12 at 22:42
  • This fiddle doesn't shows any replacement or re-attaching of the event. – vlio20 Oct 14 '12 at 07:03
  • @VladIoffe it demonstrates `this.value = null;` – Musa Oct 14 '12 at 07:05