I am using Angular ng-file-upload
(https://github.com/danialfarid/ng-file-upload) on the frontend to manage the file upload process.
Unfortunately, form contains a complex object with multiple files. Using the MultipartFormData
(https://www.playframework.com/documentation/2.5.x/ScalaBodyParsers) on the server side I have successfully decomposed the uploaded content and can read it from the request.body
.
Now, to my surprise, I do not have a simple Json Objects
but rather a strangely formed datatype, described on the ng-file-upload
website as:
(...) server implementations expecting nested data object keys in .key or [key] format. Example: data: {rec: {name: 'N', pic: file}} sent as: rec[name] -> N, rec[pic] -> file
data: {rec: {name: 'N', pic: file}, objectKey: '.k'} sent as: rec.name -> N, rec.pic -> file
So far I have managed to bring all the data to a common MultipartFormData.Part
type, using the DataPart
and FilePart
like this:
val opts = body.dataParts.map {
case (key, values) => DataPart(key, values.head)
}
val parts = opts ++ body.files
So I am now left with a quite unfortunate Iterable[Part]
:
0 = {MultipartFormData$DataPart@86271} "DataPart(arabic[active],false)"
1 = {MultipartFormData$DataPart@86273} "DataPart(english[active],true)"
2 = {MultipartFormData$DataPart@86277} "DataPart(english[url],2132132132)"
...
7 = {MultipartFormData$FilePart@76473} "FilePart(english[image],fb_icon_325x325.png,Some(image/png),TemporaryFile(/tmp/playtemp5909927824995768544/multipartBody8348573128070542611asTemporaryFile))"
Each object name
contains the key
of it's Json structure and its according value
. Now instead of key[level1][level2]
I would like to parse it to objects, in my case:
case class PcBanner(english: PcBanners, arabic: PcBanners, kurdish: PcBanners)
case class PcBanners(active: Boolean, url: Option[String], image: Option[String])`
I hope you got the idea.
The question
I know I could try to parse the name
strings trying to fit it to objects, but I believe I made a mistake someway in the middle.
Is there a way to parse this structure into the objects, using field names as a reference? Any build in Play functions or alike?
Thanks for help!
As I stated in the title my case was to send images. As you would expect, I am also presenting a preview and the files currently saved in the database.
Considering all pros and cons I have decided to send all the data in JSON format, both ways. Meaning that the images are encoded and sent along in JSON structure.Despite the fact that above solution looks very convenient it actually creates new problems during the implementation.
Not going deeper into this faulty solution I have used the @danial advice:
My solution
If anyone would like to use similar approach to mine I present my answer. On the front-end side I have decided used ng-file-upload library. Binding it to HTML component with
ngf-select
withngf-drop
which enables the component:Inside the upload tag I put the image preview. This works flawlessly. If the image is not selected I use the image saved in the db.
The data and images do not share the model anymore. The upload function looks as follow:
Putting together all the above gave me the output data object:
On the server side the JSON matches the prepared case class and is parsed with build-in Jackson parser, allowing for easy object manipulation. The image has to be manually selected:
Extracting the files from body can be done with build in function
.file
:Enjoy!