Using Files from web browser and AngularJS: Select, Drag'n Drop, Read content, Upload to springboot
May 16, 2017
Files sandbox possibilities in Web Browser
Due to security restrictions, it is not possible from a web browser to perform Javascript operations on files,
unless the user has manually choosen a file.
This little demo project shows how to perform operations on files using AngularJS (and springboot on server-side):
Usually, ng-model binding works… except for this input type (??)</BR>
You simply use the javascript File[] from your controller. It contains “trusted javascript file”, than you can read.
The directive “set-model-on-change” is custom, to bind “change” DOM events to angular for the input type=”file”.
You can see log in chrome dev tools after selecting 2 files:
Drag'n Drop files
Another nice way of selecting Files is to use Drag’n Drop: you drag a file from your system file explorer,
and drop it into a html Drop zone that accept you files.
Here is a drop-zone, using a custom AngularJS directive.
This directed is adapted from draganddrop.js, /*! Angular draganddrop v0.2.2 | (c) 2013 Greg Bergé | License MIT */
I have adapted it because I could not make it work on the filtering of accepted mime-types files.
In the js-part, I implements the 3 callbacks method onDragOver(), dropAccept() and onDrop().
The important one is onDrop() that simply get the dropped files and store them as angularJs model values (avoiding duplicates files based on their name+size+modifDate).
Notice that the file full path can not be consulted from Javascript, only the name.
You can see logs in chrome:
Read Files content
After selecting/dropping files, click on button “Read selected files”, and the content will be read and displayed in textarea.
Here is the code in html
In Javascript, it is a bit more difficult because all I/O reading are asynchronous methods, with callbacks.
Also notice that the callback need to call angularJS “$scope.apply()” to perform a refresh.
If you need to load multiple files, and call a single callback at the end, you have to chain callbacks…
A common way for that is to use $q Promises, and resolve “$q.all([ promise0, promise1 ]).then(..)”.
Upload file content to server
There are many ways to submit content data to server.
This can be a multi-part files, or simply a http Rest body request with “Content-type: application/whatever” …but maybe not “application/json” which is default when using AngularJS.
You can event wrap the bytes array content into one a the field of a regular json object, and send the json..
Uploading using MultipartFile
In springboot,
If you have to upload only a fixed number of file(1,2..) whith given part name (like “attachment1”, “attachement3, “video”…), you can do this in springboot:
Uploading using Request Body Content
This method is more natural for a Rest endpoint, in particular when using curl:
In Javascript, the difficulties are 1/ to read the file with async callback, then 2/ obtain a “Blob” to convert to “Int8Array”,
submit using $http.post() without transforming to json, and finally change default http header to remove ‘Content-Type: application/json’.
From java, it is easy to handle… and there are also several possibilities in springboot:
you can bind method parameters as HttpServletRequest, and @RequestBody InputStream, or as @RequestBody byte[].
The simpler in springboot is using byte[]:
2 remarks in java:
the @PathVariable by default "{fileName}" would prune the file name extension... you have to use a regular expression: "{fileName:.+}"
you need to override the default "application/json" to accept all mime-types: consumes=MediaType.ALL_VALUE
Conclusion
Javascript File API works great, and are really simple !