Diego, correct me if I'm wrong, the example on Assembla still uses regular upload technique, but wraps it into iframe, so it feels like ajax, is this right?
As I understand Lift's liftAjax.js doesn't support ajax file uploads. In other words liftAjax.js doesn't know how to construct jQuery ajax call that includes HTML5 file APIs. I just tried fixing this by using FormData HTML5 javascript API and providing my custom JQueryArtifacts. The FormData API wraps all the form fields, including file fields into an object that jQuery can then upload. But to do this we also need to specify the `dataProcessing: false` attribute on $.ajax call.
This, along with adding method="post" enctype="multipart/form-data" to the form allows the browser to upload the file via Lift AJAX. But then the server hicks up on the request processing. The logs are also below. Do you have an idea what might be causing an error on the server side? Is it something that can be easily fixed?
In snippet:
def process() = { ... }
val onChange = SHtml.makeAjaxCall(JsRaw(s"new FormData(this.form)"))
val bindForm =
"type=file" #> SHtml.fileUpload(fph => fphBox = Full(fph), "onchange" -> onChange.toJsCmd) &
"type=hidden" #> SHtml.onSubmitUnit(process)
bindForm(
<lift:form.ajax enctype="multipart/form-data" method="post">
<input type="file"></input>
<input type="hidden"></input>
</lift:form.ajax>)
"type=submit [onclick]" #> SHtml.makeAjaxCall(JsRaw(s"new FormData(this.form)"))
In Boot:
LiftRules.jsArtifacts = new JQueryArtifacts {
override def ajax(data: AjaxInfo): String = {
"jQuery.ajax(" + toJson(data, S.contextPath,
prefix =>
JsRaw("liftAjax.addPageNameAndVersion(" + S.encodeURL(prefix + "/" + LiftRules.ajaxPath + "/").encJs + ", version)")) + ");"
}
private def toJson(info: AjaxInfo, server: String, path: String => JsExp): String =
(("url : " + path(server).toJsCmd) ::
"data : " + info.data.toJsCmd ::
"processData : " + JsRaw("!(" + info.data.toJsCmd + " instanceof FormData)").toJsCmd ::
("type : " + info.action.encJs) ::
("dataType : " + info.dataType.encJs) ::
"timeout : " + info.timeout ::
"cache : " + info.cache :: Nil) ++
info.successFunc.map("success : " + _).toList ++
info.failFunc.map("error : " + _).toList mkString ("{ ", ", ", " }")
}
Error log:
2014-11-05 22:03:30,456 [qtp1728293208-163032] ERROR net.liftweb.http.LiftRules - Exception being returned to browser when processing /ajax_request/F847084957972BAZTO3-00/
java.lang.IllegalArgumentException: !hex:f4
at org.eclipse.jetty.util.TypeUtil.convertHexDigit(TypeUtil.java:369)
at org.eclipse.jetty.util.UrlEncoded.decodeUtf8To(UrlEncoded.java:511)
at org.eclipse.jetty.util.UrlEncoded.decodeTo(UrlEncoded.java:565)
at org.eclipse.jetty.server.Request.extractParameters(Request.java:290)
at org.eclipse.jetty.server.Request.getParameterNames(Request.java:723)
at net.liftweb.http.provider.servlet.HTTPRequestServlet.params$lzycompute(HTTPRequestServlet.scala:80)
at net.liftweb.http.provider.servlet.HTTPRequestServlet.params(HTTPRequestServlet.scala:80)
at net.liftweb.http.Req$$anonfun$11.apply(Req.scala:493)
at net.liftweb.http.Req$$anonfun$11.apply(Req.scala:452)
at net.liftweb.http.AvoidGAL.thunk$lzycompute(Req.scala:355)
at net.liftweb.http.AvoidGAL.thunk(Req.scala:355)
at net.liftweb.http.Req$$anonfun$18.apply(Req.scala:506)
at net.liftweb.http.Req$$anonfun$18.apply(Req.scala:505)
at net.liftweb.http.Req.x$49$lzycompute(Req.scala:965)
at net.liftweb.http.Req.x$49(Req.scala:961)
at net.liftweb.http.Req.__params$lzycompute(Req.scala:962)
at net.liftweb.http.Req.__params(Req.scala:962)
at net.liftweb.http.Req._params(Req.scala:939)
at net.liftweb.http.Req.params$lzycompute(Req.scala:969)
at net.liftweb.http.Req.params(Req.scala:969)