Why file open dialog opens twice on clicking the button in FireFox
Asked Answered
R

5

7

I have a file <input> field and a <span> decorates the input field:

<span class="span5 btn btn-primary btn-file" id="chose_files_btn" onclick="filechose_button.click()">chose files
    <input id="filechose_button" type="file" name="fileData" size="1" style="display: none"/>
</span>

While the behavior of this is as I suppose in Chrome and Safari, FireFox opens two file input dialogs on clicking the button(span).

Why could happen so?

I assume, that file input field is invisible and only access to it is through the span with a button behavior.

Update:

if I put the <input> outside of <span> it behaves normally.

 <span class="span5 btn btn-primary btn-file" id="chose_files_btn" onclick="filechose_button.click()">chose files</span>
 <input id="filechose_button" type="file" name="fileData" size="1" style="display: none"/>

JSFiddle

but why on inside position it does not?

Rosas answered 30/4, 2013 at 5:4 Comment(8)
Have you tried putting the onclick within the input tag?Sellma
remove onclick from span and see..Bencion
no, but then I should do the input renderable (and it breaks the span element)Rosas
I believe filechose_button.click() is doing it. remove the .click()Sellma
remove the filechose_button.click() makes the button inoperative.Rosas
just the .click(), are you using jquery?Sellma
same problem (the button becomes inoperative)Rosas
It seems like it is opening the dialog twice because of event propagation. if you changed onclick to onchange. onchange does not have event propagationSellma
T
9

It is because of event propagation. When you click on the span, click event is raised and in the click handler you have called click on input type="file" so it is calling twice.

If you will try following code it would not raise propagated event.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>

<script type="text/javascript">
 $(document).ready(function(){
 $("#chose_files_btn").click(function(event){

 filechose_button.click();
}); 
$("#filechose_button").click(function(event){
    event.stopPropagation();
});
});
</script>

<span class="span5 btn btn-primary btn-file" id="chose_files_btn">chose files
<input id="filechose_button" type="file" name="fileData" size="1" style="display:     none"/>
</span>

For more information visit this link

You should play with this to get more understanding on event propagation.

Tigrinya answered 30/4, 2013 at 6:44 Comment(1)
@NullPointer Welcome. Happy to help you. :)Tigrinya
L
8

It is because of some kind of event propagation mess

<span class="span5 btn btn-primary btn-file" id="chose_files_btn" onclick="doOpen(event)">chose files
    <input id="filechose_button" type="file" name="fileData" size="1" style="display: none"/>
</span>

And

function doOpen(event){
    event = event || window.event;
    if(event.target.id != 'filechose_button'){
        filechose_button.click();
    }
}

Demo: Fiddle

Lactometer answered 30/4, 2013 at 5:10 Comment(2)
when I put the input outside span, I do not need any js. But anyway thank you for help!Rosas
@Rosas it was my suggestion as well, but from the comments I thought it was not feasible for youLactometer
V
2

I have a complex application and from some reason the following jQuery selector:

$('input[type=file]')

returned two jQuery elements instead of one.

So calling:

$('input[type=file]').trigger('click')

Triggered two file dialog box opened one after the other.

To solve this, I only applied the click trigger on the first element

$($('input[type=file]').get(0)).trigger('click');

In addition I used unbind and stopped event propagation, here is the full code:

$('#uploadFile').click(function(evt) {                      
        evt.stopPropagation();
        evt.preventDefault();                   
        evt = evt || window.event;
        if(evt.target.id == 'uploadFile'){
            $($('input[type=file]').get(0)).trigger('click');
        }
    });

    $(':file').unbind();
    $(':file').on('change', function(evt) {                                     
        // extra non-relevant code
    });
Vigen answered 5/6, 2019 at 7:29 Comment(0)
A
0

I needed to use "unbind click" for my code to work normally.

$("#chose_files_btn").unbind( "click" ); 
$("#chose_files_btn").click(function(event){
    $("#filechose_button).click();
});

$("#filechose_button").unbind( "click" );
$("#filechose_button").click(function(event){
    event.stopPropagation();
});
Anthropogenesis answered 8/2, 2018 at 10:41 Comment(0)
S
0

Seems like there could still be situations where the DOM bounces the event around, so the technique of hiding an input field and programming it to click is susceptible. I am now working on a modal dialog in an AngularJS app (designed to be used either on mobile with cordova or on a desktop browser) that needs to launch a file picker, where this phenomena happens and none of the above techniques helped.

When I place console logs on the bouncing event, it shows that the echo can arrive up to 1 second after the original click.

Following is a solution that overcomes it by creating a small stack of events, and eliminating duplicates that happen within 2 seconds.

Cheers, Z.

<div id="fileInputImagePicker-container" onclick="openJustOnce( event )">
    <script>

        var eventRecords=[];
        const MAX_BOUNCE_DELAY = 2000;

        function addEvent( event ){
            eventRecords.push( {id: event.target.id, time: Date.now()})
        }
        function isBounceEvent( event ){
            var ret = false, now = Date.now(), latestTime=0;
            for( var i=0; i < eventRecords.length && !ret; i++ ){
                var record = eventRecords[ i ];
                if( record.time > latestTime ) latestTime = record.time;
                if( record.id === event.target.id && (now - record.time) < MAX_BOUNCE_DELAY ){
                    ret = true;
                    //console.log('BOUNCE EVENT, record=', JSON.stringify(record), ' event=', event);
                }
            }
            if( now - latestTime > MAX_BOUNCE_DELAY ) eventRecords = [];
            if( !ret ) addEvent( event );
            return ret;
        }

        function openJustOnce( event ) {
            //console.log( "container event, event=", event, " event.target=", event.target, " now=", Date.now() );
            if( isBounceEvent(event) ) {
                event.stopPropagation();
                event.preventDefault();
                //console.log( "BLOCK THIS EVENT" );
            } else {
                fileInputImagePicker.click();
                //console.log( "DONT BLOCK" );
            }
        }
    </script>

    <input type="file" accept="image/*" id="fileInputImagePicker" style="display:none" />
</div>
Stevana answered 25/2, 2018 at 4:2 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.