cljs-ajax
cljs-ajax copied to clipboard
Upload Progress Handler
Hi. Thanks for cljs-ajax!
What's the recommended way to wire up the goog.net.EventType.UPLOAD_PROGRESS
event listening? When I've registered the handler on the returned xhrio request object:
(doto x
(.setProgressEventsEnabled true)
(.listen goog.net.EventType.UPLOAD_PROGRESS progress-handler))
It does not fire. I believe it has to do with the fact that they're being registered after the send
function has been triggered. I currently can register a triggering progress handler by overriding the AjaxImpl
protocol with the following:
;; Overriding the default cljs-ajax behavior
;; In order to support :progress-handler
(extend-type goog.net.XhrIo
AjaxImpl
(-js-ajax-request
[this
{:keys [uri method body headers timeout with-credentials
response-format progress-handler]
:or {with-credentials false
timeout 0}}
handler]
(when-let [response-type (:type response-format)]
(.setResponseType this (name response-type)))
;; Check for the existence of a :progress-handler arg and register if it's there
(when progress-handler
(doto this (.setProgressEventsEnabled true)
(.listen goog.net.EventType.UPLOAD_PROGRESS progress-handler)))
(doto this
(events/listen goog.net.EventType/COMPLETE
#(do (println "Overriden Complete")
(handler (.-target %))))
(.setTimeoutInterval timeout)
(.setWithCredentials with-credentials)
(.send uri method body (clj->js headers)))))
;; Example call
(POST "upload-image"
{:body (doto (js/FormData.) (.append filename file))
:progress-handler #(println "Progress" %)
:handler #(println "Upload Image" %)
:error-handler #(println "Failed Upload" %)})
While that does work, I imagine that there's a cleaner way of registering for the upload-progress event that I'm missing. If not, I'd be happy to work on a PR to add support. Thanks!
@JulianBirch I don't think that's currently possible, so a PR would be great. I could push out a new release with the change.
I would love this functionality
You could write an interceptor to do this. And if you do, please send us the code!
Ideally, we'd like to make it work with all implementations. One of these days, XhrIo and XmlHttpRequest are both going to be old hat. :)
But don't worry too much about that. Even if it's not bulletproof, we can definitely put it somewhere.
I encountered this exact issue today, I'd love to see a lightweight way to get progress events (at least in cljs) whilst POST
ing.
Related: https://github.com/google/closure-library/blob/master/closure/goog/net/xhrio.js#L483
It looks like there's quite a bit of plumbing in place for this already. Since POST
returns a goog.net.XhrIo
instance already. Presumably, if this setProgressEventsEnabled
were set, we could just listen to the object directly.
Yeah, it shouldn't be too hard. I'm working on some other issues first, but if you want to hurry stuff along, I love pull requests.
@hironroy Actually, what you're describing is pretty much exactly how I'd do it. The catch is that we'd need to document quite heavily that it only worked for XhrIo (the perils of having multiple implementations).
One of these days I need to deprecate the XhrIo implementation: it pulls a lot of code into your project for frankly unclear benefit.
Hey guys,
I really wanted this feature so I implemented it in a fork. I am happy to submit a PR if you haven't started on this yet.
PR Preview https://github.com/JulianBirch/cljs-ajax/compare/master...RyanBertrand:master
I pushed to Clojars if you want to do a quick test. https://clojars.org/ryanbertrand/cljs-ajax
Doc
:progress-handler
- the handler function for progress events. This handler is only available when using the goog.net.XhrIo
API
Example
(ajax/PUT url
{:handler (fn [data]
(println "Success"))
:progress-handler (fn [e]
(println (str "Progress (" (.-loaded e) "/" (.-total e) ") [" (* 100 (/ (.-loaded e) (.-total e))) "]%")))
:format :raw
:body js-file})
Thanks, R
That looks excellent. Please do send it. Could I ask you to rebase onto the 0,7 branch?
I'll figure out how to do it for XmlHttpRequest. Java may have to wait.
OK, I'm pushing sorting this out properly until 0.8. The existing code will go into 0.7, but it's very XhrIo specific and plain won't work with a Java implementation. I think we're going to need two handlers: upload-progress
and download-progress
. The callback methods should probably take two parameters: byte counts current
and total
. total
will be null if we can't work it out on download.
There's a related question of the best way to hook into arbitrary events. Don't know the answer to this, or even if there is a good answer.