Home > Enterprise >  Is possible to upload files with formForWithoutJavascript in IHP?
Is possible to upload files with formForWithoutJavascript in IHP?

Time:01-09

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}

|]
  •  Tags:  
  • Related