Cookies on this site

We would like to use cookies to understand how the site is used and to measure our campaigns. Nothing is set until you choose, and you can change your mind at any time from “Cookie settings” at the foot of every page. Privacy policy

Contact UsContact Us

Resources / Blogs

Cloud & apps

Dynamic file input – teaching html some new tricks

Teaching html some new tricks - Implement a custom file upload widget using bootstrap, angularjs and jquery. Check out my two cents on the idea.

· · 4 min read

Dynamic file input

Okay, now this post might come across as a bit of a rant but could be of real use to people who are looking to implement a custom file upload widget. Lets face it, the default file input container provided by HTML is not what we’d describe as eye-candy and to top it off each browser lends its own rendering to the input tag. Heterogeneous user experience is a nightmare for designers/front-end developers. So we often rely on third party javascript to do the magic for us. However that may not always be the answer to your problems depending on the front-end framework/architecture being used in your project. I experienced this sort of problem recently while working with Angular Js as the front-end framework. I used dwr (Direct Web Remoting) module for actually handling the uploads. Relying on a third party module as an upload widget was just not working for sequential file uploads, so I applied for a more unconventional solution.

Preface:

My page consists of divs which loop and repeat the contents of my model:

<div ng-repeat=”item in itemlist”>

<form method=“post” action=“#” enctype=“multipart/form-data”>

<input id=”fileprefix{{item.itemId}}” type=”file”>

<button type=”button” ng-click=”controllerFileUpload(item,’fileprefix’+item.itemId)”>

Upload

</button>

</form>

</div>

Each div will have an input field containing an unique id and the button passes the model “item” and the file contents from the input field with the unique id.

It was pretty difficult use third party module for this use case since most of them use jquery to identify the input tag id, which of course, was provided dynamically by Angular. And so I ventured to create my own widget:

<div ng-repeat=”item in itemlist”>

<form method=“post” action=“#” enctype=“multipart/form-data”>

<input id=”fileprefix{{item.itemId}}” type=”file” onclick=”updatefield()” style=”display: none;”>

<div class=”input-append”>

<input id=filenamecontainer{{item.itemId}} type=”text” placeholder=”Choose File” disabled>

<a class=”btn btn-white” onclick=”copycarry()”>Browse Files</a>

<button type=”button” ng-click=”controllerFileUpload(item,’fileprefix’+item.itemId)”>

Upload File

</button>

<button type=”button” onclick=”resetval()”>
Clear selection

</button>

</div>

</form>

</div>

What we have here is two input fields: one that is actually used to store the file value is hidden from view using “display: none” and the second input field is used to display file name to the user. The output of this markup looks like:

In my case I’ve used font-awesome icons instead of text for the buttons, but to each his own. Now pay attention to the onclick events associated with the buttons and input fields. Before I delve into their code, notice that three of those fields have the normal javascript “onclick” attribute and the “Upload File” button has Angular Js “ng-click” attribute. This smells of complication, but let me justify myself here: Angular Js has access to a lot of Jquery tools with the presence of Jquery in your markup and if it isn’t included in your markup Angular has a built-in JQ-lite toolbox that gives it a lot of Jquery like functionality, but the problem is that it isn’t as convenient manipulating the DOM through Angular as it is with Jquery. You get more tools in Jquery and if you want DOM manipulation from Angular you’ll have to manually call “$apply” service which could lead to complication. So I opted for the best of both worlds and made use of Jquery for the DOM manipulation for styling and Angular Js for file upload. Take a look:

<script type=”text/javascript”>

function resetval(){

$(‘input[id^=”fileprefix“]’).filter(function(){

return /^fileprefixd+$/.test(this.id);

}).val(“”);

$(‘input[id^=”filenamecontainer“]’).filter(function(){

return /^filenamecontainerd+$/.test(this.id);

}).val(“”);

};

</script>

——————————————————————————————————————————–

<script type=”text/javascript”>

function copycarry(){

$(‘input[id^=”fileprefix“]’).filter(function(){

return /^fileprefixd+$/.test(this.id);

}).click();

};

</script>

——————————————————————————————————————————–

<script type=”text/javascript”>

function updatefield(){

$(‘input[id^=”fileprefix“]’).filter(function(){

return /^fileprefixd+$/.test(this.id);

}).change(function() {

$(‘input[id^=”filenamecontainer“]’).filter(function(){

return /^filenamecontainerd+$/.test(this.id);

}).val($(this).val());

});

};

</script>

The first function “resetval( )” is pretty self explanatory, it simply finds the element with id matching the regular expression “fileprefix” and “filenamecontainer” followed by a number and sets the value of that field to empty. The regular expression matching is important here because the number following the prefix in provided dynamically by Angular Js. So this way I was able to consume the dynamic nature of the id attributes.

The second function “copycarry( )” carries over the click action from the “Browse Files” button to the input field that will actually hold the file. The input file is hidden from view, but this function actually invokes the input field to open the file browser by emulating the click event.

The hidden input field also has “onclick” action attached to it. The “updatefield( )” function copies the file name value from the hidden input of type file to the visible input of type text which displays the file name to the user.

The function associated to the “Upload File” button is handled by Angular Js with the ngClick directive and the function is written into the controller which will retrieve the file from the hidden input field.

Thus, with what seems like a lot of patch work I was able to get it to work, but it does work smoothly and allows styling by simple twitter-bootstrap classes and without building any complicated custom directives in Angular Js to manipulate the DOM, we have taught a new trick to plain old HTML.

← All articles

Case studies

Cloud Consulting in practice

Client names are withheld. We are happy to share details on a call.

All case studies
  • Delivered

    On-prem → Amazon RDS

    Nonprofit

    Cloud Consulting

    Oracle from on-premises to Amazon RDS for a national nonprofit

    The nonprofit's on-premises Oracle database had become hard to maintain and scale. We planned the move with automated workflows and validation tests, migrated to Amazon RDS for Oracle with minimal disruption and left a repeatable process for future changes.

    • Automated, tested migration
    • Less day-to-day database upkeep
  • Delivered

    600k files, < 3 days

    Document management

    Microsoft

    600,000 documents moved from ImageRight to SharePoint in under three days

    A one-file-at-a-time script would have needed about 22 days of continuous running. We rebuilt the migration around a SQL work queue with parallel uploads, automatic retries and crash recovery, and it finished unattended in under three days.

    • 1,125 → 8,314 files per hour
    • Under 3 days instead of about 22
  • Delivered

    Every change, flagged

    Food manufacturing

    AI Consulting

    Label comparison agent for a national food cooperative

    Compares two versions of a product label, highlights every change, annotates the PDF and returns an audit-ready list of differences. We moved it from Copilot Studio to Azure Functions when the document processing outgrew the low-code platform.

    • Audit-ready differences in one chat turn
    • Rebuilt from low-code to cloud functions

Keep reading

All Cloud & apps articles

Moving an application to the cloud?

Request a migration plan consult. We will scope the move with you and come back with a fixed-scope plan.