Faux File Upload Input

The element <input type=”file”> is very ugly in most browsers and it seems that even Bootstrap didn’t put any effort into sprucing it up.

My end objective was to have a user press a rectangle box with a title inside which would open a file dialog and ultimately upload that file.

At first I thought this would be easy after some quick research in Google land. Not so.

Note: I’m using the jQuery 2.x library in my examples

<style>
	input {
		display:none;
	}
</style>

<form method="post" enctype="multipart/form-data">
	<div id="wrapper">click here to upload<br><br>
		<input type="file">
	</div>
</form>

<script>
	$('#wrapper').click(function(event){
    	$(':file').click();
	});
	
	$(':file').change( function() {
		$('form').submit();
	});
</script>

At first I thought it would be as easy as 1) hiding the input 2) watching the click event on the container 3) trigger the input’s click event and 4) submit the form.

But what I found out was that the event listener kept firing infinitely until the browser aborted with a “Uncaught RangeError: Maximum call stack size exceeded” error in the console. Though honestly I don’t completely understand what’s going on here, the click event by my mouse bubbles up to the child input element.

To resolve that issue I started looking for the event that was not fired by the input element:

<script>
	$('#wrapper').click(function(event){
		if( !$(event.target).is(':file') ) {
	    	$(':file').click();
	    }
	});
	
	$(':file').change( function() {
		$('form').submit();
	});
</script>

At this point @chrish on CFML Slack was helping me out and also offered up a solution were as now we are stopping propagation for the input element.

<script>
	$('#wrapper > :file').click(function(event) { event.stopPropagation(); });
	$('#wrapper').click(function(event){
    	$(':file').click();
    }
	
	$(':file').change( function() {
		$('form').submit();
	});
</script>

I ended up sticking with the first solution incorporating the “if” statement until Jessica Kennedy reminded me of a simple solution using the label element. Because this simplifies things (AKA less likely to break) I’m now sticking with this solution. Normally a label will focus on the input field when clicked on. But in this case it fires off an event to open the file dialog. I’ve tested this in Chrome, FireFox and IE 9+. I’m pretty sure the label element has some limitations what you can stick in it, so this may not always work for you. But in my case I was able to apply the Bootstrap widget classes (not seen in this example) and it worked as expected.

<style>
	input {
		display:none;
	}
</style>

<form method="post" enctype="multipart/form-data">
	<label id="wrapper">click here to upload<br><br>
		<input type="file">
	</label>
</form>

<script>
	$(':file').change( function() {
		$('form').submit();
	});
</script>
Advertisements

#file, #html, #upload

jQuery UI Dialog Centering Issue

I’m working with some code that’s been worked over many, many times over the years. It could a thorough scrubbing, but that’s not in the scope of my request.

I just upgraded the jQuery UI to version 1.9.2 and jQuery to 1.8.3 and added a simple dialog.

test_dialogIt was expected that the dialog would center itself to the browser window. However it appeared to be centering itself to the html element and scrolling the page to make it centered if the content was longer than the window height.

Here’s the code:

<html>
<head>
    <title>My Title</title>
</head>
<body>
    <div id="userNoticeDialog" style="display: none;" title="Notice">
        test content
    </div>

    <script type="text/javascript">
        $("#userNoticeDialog").dialog();
    </script>
</body>
</html>

After a process of elimination and seeing that there was no doctype declared, I tried adding a doctype. That resolved the issue.

<!DOCTYPE html>
<html>
<head>
    <title>My Title</title>
</head>
<body>
    <div id="userNoticeDialog" style="display: none;" title="Notice">
        test content
    </div>

    <script type="text/javascript">
        $("#userNoticeDialog").dialog();
    </script>
</body>
</html>

I believe the reason was the lack of a DOCTYPE caused the (Chrome) browser to go into quirks mode, while the inclusion of the DOCTYPE caused the (Chrome) browser to go into standards mode. However, I’m not sure how to detect which mode the Chrome browser is currently in. Does anyone know?

#center, #dialog, #doctype, #html, #jquery, #ui