dominikh / go-js-dom

MIT License
252 stars 42 forks source link

Add a method to access the File content. #32

Closed tbellembois closed 8 years ago

tbellembois commented 8 years ago

Is it possible to add a method to retrieve the content of a File object to be able to send it with a POST method to the server ?

fileSelect := d.GetElementByID("import-file").(*dom.HTMLInputElement)
file := fileSelect.Files()[0]
...
resp, err := http.Post("/import/", "multipart/form-data", [the-file-content])
...

I currently do this in Javascript with:

var file = fileSelect.files[0];
var formData = new FormData();
formData.append('importFile', file, file.name);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/import/', true);
...

Or any way to do this with another method? Thanks.

dominikh commented 8 years ago

/cc @shurcooL because I have no idea what the actual API is and what we should add, if anything.

dmitshur commented 8 years ago

You should be able to do this already... mostly.

Is it possible to add a method to retrieve the content of a File object

I think @tbellembois was referring to dom.File which is currently documented as:

File represents files as can be obtained from file choosers or drag and drop. The dom package does not define any methods on File nor does it provide access to the blob or a way to read it.

From https://developer.mozilla.org/en-US/docs/Web/API/File:

A File object is specific kind of a Blob, and can be used in any context that a Blob can. In particular, FileReader, URL.createObjectURL(), createImageBitmap(), and XMLHttpRequest.send() accept both Blobs and Files.

So, you should be able to do:

fileSelect := d.GetElementByID("import-file").(*dom.HTMLInputElement)
file := fileSelect.Files()[0]
...
req := xhr.NewRequest("POST", "/import/")
err := req.Send(file.Object)
...

If you'd like to use net/http package to send the contents of file, you will need to use FileReader which dom does not currently cover. /cc @dominikh

// blobToBytes converts a Blob to []byte.
func blobToBytes(blob *js.Object) []byte {
    var b = make(chan []byte)
    fileReader := js.Global.Get("FileReader").New()
    fileReader.Set("onload", func() {
        b <- js.Global.Get("Uint8Array").New(fileReader.Get("result")).Interface().([]byte)
    })
    fileReader.Call("readAsArrayBuffer", blob)
    return <-b
}

fileSelect := d.GetElementByID("import-file").(*dom.HTMLInputElement)
file := fileSelect.Files()[0]
...
b := blobToBytes(file.Object) // File can be treated as a Blob.
resp, err := http.Post("/import/", "multipart/form-data", b)
...
tbellembois commented 8 years ago

Thanks. The xhr.NewRequest(...) works. I have not tried the second one yet.

I had to change few lines in the server side code from file, _, err := r.FormFile("importFile") to file, err := ioutil.ReadAll(r.Body) to process the file.

Many thanks for your quick reply.