简体   繁体   中英

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

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?

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

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.

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

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>

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

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM