I have a function that reads a file using js/FileReader.
:
(defn read-file [file]
(let [js-file-reader (js/FileReader.)]
(set! (.-onload js-file-reader)
(fn [evt]
(let [result (-> evt .-target .-result)
array (js/Uint8Array. result)]
{:content array}))) ; <- This is the value that 'read-file' should return
(.readAsArrayBuffer js-file-reader file)))
The problem is that I would like it to return the value of the .-onload
method of the FileReader
, but I only get (of course) the value of (.readAsArrayBuffer js-file-reader file)
which, naturally, is undefined
.
Thank you very much!
After trying with Martin Půda's answer, I think that the problem has to do with an asyncrhonous thing. I tested this code:
(defn read-file [file]
(let [js-file-reader (js/FileReader.)
reading-result (atom)
done? (atom false)]
(set! (.-onload js-file-reader)
(fn [evt]
(let [result (-> evt .-target .-result)
array (js/Uint8Array. result)]
(reset! reading-result {:content array})
(reset! done? true)
(js/console.log "in: " (:content @reading-result)))))
(.readAsArrayBuffer js-file-reader file)
;; (while (not @done?) (js/console.log (.-readyState js-file-reader)))
(js/console.log "out: " @reading-result)
@reading-result))
I get first the log of out: undefined
, and then the log of in:
(with the desired result).
When I uncomment the line (while...)
, I get an infinite loop of 1
's... So I think that the function never notices that the FileReader
was done... I don't know how to solve this...
After much reading, I solved it using a callback function:
(ns lopezsolerluis.fits)
(defn read-file [file callback]
(let [js-file-reader (js/FileReader.)]
(set! (.-onload js-file-reader)
(fn [evt]
(let [result (-> evt .-target .-result)
array (js/Uint8Array. result)]
(callback array))))
(.readAsArrayBuffer js-file-reader file)))
Then read-file
is called from this:
(ns lopezsolerluis.annie-web)
(defn procesar-archivo [result]
(js/console.log "Bloques: " result))
(defn input-file []
[:input {:type "file" :id "fits" :name "imagenFits" :accept "image/fits"
:on-change (fn [this]
(if (not (= "" (-> this .-target .-value)))
(let [^js/File file (-> this .-target .-files (aget 0))]
(fits/read-file file procesar-archivo)))
(set! (-> this .-target .-value) ""))}])
I added the namespaces because it surprised me that the callback machinery worked even across namespaces. Well, maybe it shouldn't surprise me; but I am learning and was a new concept for me. :)
I answer my question in case it's useful for others (it costed me a lot! :))