dojo 1.10 How to read text file a user has picked with a file picker

1k views Asked by At

Using Dojo 1.10 (for consistency with existing GUI), I want the user to select a local JSON text file via a file picker, then read the file's contents into a JavaScript variable. Must work in IE9+. A RESTful server is available if required, but not mandatory.

I had some limited success with dojox.form.Uploader. The file picker and upload worked; the file contents could be read on the server, but there was no way to return the file contents back to the client. The browser also redirected to the form's URL which I don't want and event.preventDefault() on the form's submit didn't fix this.

Attempting to submit the HTML form containing the dojox.form.Uploader using dojo.request.iframe (as per this) resulted in a 415 Unsupported Media Type error.

HTML's FileReader looks most promising but isn't supported in IE9 and doesn't use Dojo.

There has to be a way to do this, can someone please help?

1

There are 1 answers

0
MeterLongCat On BEST ANSWER

I got this to work. Just sharing the solution for the benefit of others. Technologies used:

  • Jersey 2.x
  • Jackson 2.4.x
  • Jetty 9
  • Java 8
  • Dojo 1.10.x

Below is the HTML <form> containing the dojox.form.Uploader, allowing the user to pick a file to upload. Note that uploadOnSelect is set to false so we can upload manually via JavaScript:

<form id="uploadForm" enctype="multipart/form-data" >
    <input id="myUploader" type="file" name="theFile" data-dojo-type="dojox/form/Uploader" data-dojo-props="uploadOnSelect: false" />
</form>

Below is the JavaScript code that hooks into the "change" event of the Uploader, and uses a dojo.request.iframe to upload to a REST server via POST:

require([
    "dijit/registry", 
    "dojo/on", 
    "dojo/dom", 
    "dojo/request/iframe", 
    "dojo/json", ...], 
function(registry, on, dom, iframe, json){ 
    ...
    var me = this;
    on(registry.byId("myUploader"), "change", function() { me._getFileJSON.apply(me, arguments); });
    ...
    _getFileJSON : function() {
        var me = this;
        var td = iframe.post("rest/getFile", {
            form: dom.byId("uploadForm"),
            preventCache: true
        }).then(function(data) {
            ... use JSON returned
        }, function(error) {
            console.error(error);
        });
    }
    ...
});

Below is the server-side method that handles the POST, reads the given file and returns its JSON contents. Very important that the JSON to be returned is wrapped in the full <html> tag shown, including the <textarea> so that the dojo.request.iframe can read the response. Refer to dojox.form.Uploader documentation.

MyPersistenceObj is a simple POJO that matches the JSON structure in the received file. The transformation from JSON to POJO and back to JSON isn't strictly necessary, but provides the ability for additional processing using the POJO (not included for brevity).

@POST
@Path("/getFile")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_HTML)
public String uploadFile(
    @FormDataParam("theFile") InputStream inData,
    @FormDataParam("theFile") FormDataContentDisposition fileDetail) {

    try {
        ObjectMapper mapper = new ObjectMapper();
        MyPersistenceObj data = mapper.readValue(inData, MyPersistenceObj.class);

        ObjectWriter ow = mapper.writer();
        String dataAsJson = ow.writeValueAsString(data);
        return "<html><head></head><body><textarea>" + dataAsJson + "</textarea></body></html>";
    } catch (Exception e) {
        return "<html><head></head><body><textarea>{ \"error\" : \"invalid JSON: "
            + (e.getMessage() != null ? e.getMessage().replaceAll("[\"'\\r\\n]", "") : "<N/A>")
            + "\" }</textarea></body></html>";
    }
}

I again acknowledge how to upload file using dojo, which presents a partial solution to this.