File uploads in IHP seems to behave quite differently in a formFor without JS compared to formForWithoutJavascript.
I wanted to try to perform file uploads without JS as I figured there are parts of my apps that might be better off without Turbolinks and Morphdom.
I have created a Gitpod demonstrating the problem with a simple File record in the database: https://olive-bonobo-8tmc7rr9.ws-eu25.gitpod.io/
Also repo in case that works better: https://github.com/kodeFant/file-upload-nojs
In Web/View/Files/New.hs, we have a standard form with file uploads and a preview and this seems to work well.
renderForm :: File -> Html
renderForm file = formForWithoutJavascript file [hsx|
<input
type="file"
name="fileUrl"
accept="image/*"
data-preview="#fileUrlPreview"
/>
<img id="fileUrlPreview"/>
{submitButton}
|]
The upload action does not behave as I expect. The filename is saved in the record, but without a path. And putStrLn $ show fileUrl prints Nothing, so it seems like the file itself is not picked up.
action CreateFileAction = do
let file = newRecord @File
let fileUrl = fileOrNothing "fileUrl"
putStrLn $ show fileUrl
file
|> buildFile
|> ifValid \case
Left file -> render NewView { .. }
Right file -> do
file <- file |> createRecord
setSuccessMessage "File created"
redirectTo FilesAction
Is this fixable in js-less forms or is it only supported with Turbolinks/Morphdom?
CodePudding user response:
Without testing this I think one difference between the JS and the no JS version is that the JS version automatically sets enctype="multipart/form-data" on the form when a file input exists.
The no JS solution is not using enctype="multipart/form-data" on the form. Therefore the file is encoded using the default application/x-www-form-urlencoded. That encoding doesn't support file names. Therefore the file name is Nothing.
Try something like this to validate this hypthosis:
renderForm :: File -> Html
renderForm file = [hsx|
<form method="POST" action={CreateFileAction} enctype="multipart/form-data">
<input
type="file"
name="fileUrl"
accept="image/*"
data-preview="#fileUrlPreview"
/>
<img id="fileUrlPreview"/>
<button type="submit" >Upload</button>
</form>
|]
CodePudding user response:
Based on Marc's helpful answer, I was able to get file uploads to work as expected by setting custom form options like this:
customFormOptions :: FormContext File -> FormContext File
customFormOptions formContext =
formContext
|> set #disableJavascriptSubmission True
|> set #customFormAttributes [ ("enctype", "multipart/form-data") ]
Then I could write a form this way:
renderForm :: File -> Html
renderForm file = formForWithOptions file customFormOptions [hsx|
<input
type="file"
name="fileUrl"
accept="image/*"
data-preview="#fileUrlPreview"
/>
<img id="fileUrlPreview"/>
{submitButton}
|]
