How to do file upload in ajax form?

1,142 views
Skip to first unread message

ivans...@gmail.com

unread,
Dec 29, 2012, 12:40:25 PM12/29/12
to lif...@googlegroups.com
I can't get file upload to work in an Ajax form. Oriented by this example, and a working Ajax form which I had, I ended with the appended code. Everything works correctly besides onFileUpload is never called and this, when the form is submitted, the fileHolder box is empty.

Thanks in advance!

HTML:

<form class="lift:form.ajax?form=post;multipart=true"> 
<div class="lift:MySnippet">
Name: <input name="name"><span class="lift:Msg?id=nameerror&errorClass=error">error</span><br>
Image: 
<input id="image" name="image" class="text" type="text" />
<input type="submit" value="Add">
</div>
</form>

also tried
<form class="lift:form.ajax" form="POST" multipart="true">




Snippet:

object MySnippet {
  
    object fileName extends RequestVar[Box[String]](Full(Helpers.nextFuncName))
    object imageFile extends RequestVar[Box[FileParamHolder]](Empty)
    
    var fileHolder : Box[FileParamHolder] = Empty
    
 def render = {
   var name = "item name"
   var image = "image path"
   def process(): JsCmd= {
S.error("nameerror", "Name is empty");
 
Garbage.create.name(name).activeImageId(999).save
     
Alert("fileHolder:" + fileHolder)
   }
   
   def onFileUpload(fph:FileParamHolder) = {
    println("onFileUpload called ********");
   
    fileHolder = Box !! fph;
   }
   
   "name=name" #> SHtml.text(name, name = _, "id" -> "the_name") &
   "type=submit" #> SHtml.ajaxSubmit("Add", process) &
   "name=image" #> SHtml.fileUpload(onFileUpload)
 }
}

Diego Medina

unread,
Dec 29, 2012, 12:55:53 PM12/29/12
to Lift
ajax file upload are a bit different than regular forms (as you have
seen already).

Whenever I need an ajax file upload, I use

http://blueimp.github.com/jQuery-File-Upload/

and then setup a lift rest endpoint to receive the file.

The integration is pretty straight straightforward and the plugin
handles all the browser compatibility issues.


Regards,

Diego
> --
> --
> Lift, the simply functional web framework: http://liftweb.net
> Code: http://github.com/lift
> Discussion: http://groups.google.com/group/liftweb
> Stuck? Help us help you:
> https://www.assembla.com/wiki/show/liftweb/Posting_example_code
>
>
>



--
Diego Medina
Lift/Scala Developer
di...@fmpwizard.com
http://www.fmpwizard.com

Chenguang He

unread,
Dec 29, 2012, 2:01:46 PM12/29/12
to lif...@googlegroups.com
Here is a working snippet in our project. It original made by DPP

Hope it can help you

package code.snippet
import net.liftweb.http._
import net.liftweb._
import common.Full
import util._
import net.liftweb.http.provider.servlet.HTTPServletContext
import code.model.resume
import java.io._
import net.liftweb.util._
import net.liftweb.common._
import java.util.Date
import code.model._
import code.lib.util._
 
class writingresume extends LiftScreen{
  override protected def hasUploadField = true
  val resumeupload = makeField[Array[Byte], Nothing]("Upload Resume:  ", new Array[Byte](0),
    field => SHtml.fileUpload(fph => storeFile(fph)),
    NothingOtherValueInitializer)
  var filename = ""
  def storeFile (file : FileParamHolder): Box[File] =
  {
    getBaseApplicationPath match
    {
      case Full(appBasePath) =>
      {
        val d:Date = new Date()
        filename = d.getTime+file.fileName
        var uploadDir = new File(appBasePath + "uploads")
        val uploadingFile = new File(uploadDir, filename)
 
        var output = new FileOutputStream(uploadingFile)
        try
        {
          output.write(file.file)
        }
        catch
          {
            case e => println(e)
          }
        finally
        {
          output.close
          output = null
        }
 
        Full(uploadingFile)
      }
      case _ => Empty
    }
  }
  def getBaseApplicationPath: Box[String] =
  {
    LiftRules.context match
    {
      case context: HTTPServletContext =>
      {
        var baseApp: String = context.ctx.getRealPath("/")
 
        if(!baseApp.endsWith(File.separator))
          baseApp = baseApp + File.separator
 
        Full(baseApp)
      }
      case _ => Empty
    }
  }
 
}


Chenguang He




Chenguang He




ivans...@gmail.com

unread,
Dec 29, 2012, 4:59:17 PM12/29/12
to lif...@googlegroups.com
Hi,

thanks for your answer. The plugin looks great, I added it to my project. But I'm stuck in the server part.

In main.js I replaced url: 'server/php/' with url: 'mytest'.

I created a RestHelper for this and it works, it's being called when I click to upload the image. But I don't know how to get the file's data there...

I looked in the original file UploadHandler.php and there it uses request variables like $_FILES or $_SERVER, how do I access this with Lift?

Diego Medina

unread,
Dec 29, 2012, 5:48:01 PM12/29/12
to Lift
This is from a personal project
https://gist.github.com/a6715d1e3664f73cd03a
hope it helps.

Diego

Ivan Schuetz

unread,
Dec 29, 2012, 7:05:49 PM12/29/12
to lif...@googlegroups.com
Thanks a lot Diego, got it working! This was the crux:

req.uploadedFiles

But the rest of the code is also very helpful.

Antonio Salazar Cardozo

unread,
Dec 30, 2012, 12:03:32 AM12/30/12
to lif...@googlegroups.com
I basically hate having to do extra work, plugin or otherwise, for file upload. As such, I've written some code that lets you use regular Lift AJAX forms with file fields and have them run async:


There are two things there. One is something you have to run on Boot (in Boot.scala or something invoked from there). It handles some IE-specific nastiness related to the second part.

The second part retargets the form at #form-wrapper form (you can change this selector obviously) to submit to an iframe instead of submitting via AJAX. Everything else about the submission remains the same, including the evaluation of the returned JavaScript. In Lift, you do the same thing you always would for an AJAX form, throwing in a regular file upload field as usual, and everything will Just Work (tm).
Thanks,
Antonio
Reply all
Reply to author
Forward
0 new messages