Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not able to upload files with form #10047

Closed
MrMooky opened this issue May 13, 2024 · 5 comments
Closed

Not able to upload files with form #10047

MrMooky opened this issue May 13, 2024 · 5 comments
Labels

Comments

@MrMooky
Copy link
Sponsor

MrMooky commented May 13, 2024

Bug description

I am not able to upload files when sending the form via AlpineJS. The error message states that "Dateien" has to be an array. I also tried setting max_files to 1, but then the error states that 1 file is required, even though a file has been added.

Screenshot 2024-05-13 at 10 04 51

While looking for a solution, I stumbled upon this issue, which is essentially the same problem, only that I'm sending via AlpineJS.

This is the JS code:

document.addEventListener('alpine:initializing', () => {
    Alpine.data('formHandler', () => ({
        processing: false,
        success: false,
        form: null,
        init() {
            this.form = this.$form(
                'post',
                this.$refs.form.getAttribute('action'),
                JSON.parse(this.$refs.form.getAttribute('x-data')).form,
                {
                    headers: {
                        'X-CSRF-Token': {
                            toString: () => this.$refs.form.querySelector('[name="_token"]').value,
                        }
                    }
                }
            )
        },
        submit() {
            this.processing = true;
            this.form.submit()
                .then(response => {
                    {{ if (success_action == 'redirect') }}
                        window.location.replace("{{ success_redirect }}");
                    {{ else }}
                        this.processing = false;
                        this.success = true
                        this.$refs.form.reset()
                    {{ /if }}
                })
                .catch(error => {
                    console.log(error);
                    this.processing = false;
                })
        }
    }))
})

This is the rendered field in question:

<input type="file" name="dateien[]" multiple="" x-model="form.dateien" @change="form.validate('dateien')" :aria-invalid="form.invalid('dateien')">

How to reproduce

Create a form and enable attachments. Then use the JS from the bug description to try to send the form.

Logs

No response

Environment

Environment
Application Name: ABC
Laravel Version: 10.48.10
PHP Version: 8.2.16
Composer Version: 2.7.6
Environment: local
Debug Mode: ENABLED
URL: abc.test
Maintenance Mode: OFF

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: statamic
Database: mysql
Logs: stack / single
Mail: postmark
Queue: sync
Session: file

Statamic
Addons: 2
Antlers: runtime
Sites: 1
Stache Watcher: Disabled
Static Caching: Disabled
Version: 4.57.3 PRO

Statamic Addons
jacksleight/statamic-bard-texstyle: 3.2.0
mitydigital/sitemapamic: 2.3.9

Installation

Fresh statamic/statamic site via CLI

Additional details

No response

@duncanmcclean
Copy link
Member

Form uploads seem to be generally working for me, I've tested in a few sites on the latest version which probably means it's a templating/JS issue.

Can you provide the template where you're using the {{ form }} tag?

@ryanmitchell
Copy link
Contributor

If youre using Alpine in front end forms, you need to index the field... eg

            <input
                id="assets_field"
                name="assets_field[]"
                type="file"
                @change="form.assets_field[0] = $event.target.files[0]; form.validate('assets_field[0]')"
            />

or alternative this should work (untested)

            <input
                id="assets_field"
                name="assets_field[]"
                type="file"
                @change="form.assets_field = $event.target.files; form.validate('assets_field')"
            />

using x-model doesn't work.

@MrMooky
Copy link
Sponsor Author

MrMooky commented May 14, 2024

Can you provide the template where you're using the {{ form }} tag?

Sure, this is the HTML. The partial form_handler (at the bottom) includes the JS from above.


{{ if form:handle }}
    {{ form:create :in="form:handle" js="alpine:form" attr:x-ref="form" }}
        <span class="absolute top-[-300px]" x-ref="anchor" xmlns="http://www.w3.org/1999/html"></span>
            <div x-data="formHandler()" x-cloak class="{{ class }}">
                <div {{ if success_action == 'notification' }}x-show="success === false" x-transition{{ /if }}>

                {{# Honeypot spam protection. #}}
                <div class="hidden">
                    <label class="font-bold" for="{{ honeypot }}">{{ trans:strings.form_honeypot }} <sup class="text-yellow-400">*</sup></label>
                    <input class="w-full form-input" id="{{ honeypot }}" type="text" name="{{ honeypot }}" tabindex="-1" autocomplete="off" />
                </div>

                {{ sections }}
                    <fieldset class="grid w-full gap-6 md:grid-cols-12">
                        {{ if display || instructions }}
                            <span class="md:col-span-12">
                                {{ display ?= {partial:typography/h2 class="mb-2" as="legend" content="{trans :key="display"}"} }}
                                {{ instructions ?= {partial:typography/p content="{trans :key="instructions"}"} }}
                            </span>
                        {{ /if }}

                        {{ fields }}
                            <template x-if="{{ show_field }}">
                                <div class="{{ input_type == 'hidden' ?= 'hidden' }} flex flex-col space-y-3
                                    {{ width == '25' ?= 'md:col-span-3' }}
                                    {{ width == '33' ?= 'md:col-span-4' }}
                                    {{ width == '50' ?= 'md:col-span-6' }}
                                    {{ width == '66' ?= 'md:col-span-8' }}
                                    {{ width == '75' ?= 'md:col-span-9' }}
                                    {{ width == '100' ?= 'md:col-span-12' }}">
                                    <div class="relative">
                                        {{ if type == "toggle" || type == "checkbox" || type == "radio" }}
                                            {{ field }}
                                        {{ elseif type != "hidden" }}
                                            {{ field }}

                                            <label for="{{ handle }}" class="absolute -translate-y-1 scale-75 top-2 peer-focus:px-2 peer-focus:text-blue-600 peer-placeholder-shown:scale-100 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-[26px] peer-focus:top-2 peer-focus:scale-75 peer-focus:-translate-y-1 left-1 text-sm text-gray-500 transition-floatinglabels duration-300 transform z-10 origin-[0] px-2">
                                                {{ trans :key="display" }}

                                                {{ if validate | contains('required') }}
                                                    <sup class="font-semibold text-green-500">*</sup>
                                                {{ /if }}

                                                {{ if instructions }}
                                                    {{ partial:typography/p class="my-1 text-sm" content="{trans :key="instructions"}" }}
                                                {{ /if }}
                                            </label>
                                        {{ /if }}
                                    </div>
                                </div>
                            </template>
                        {{ /fields }}
                    </fieldset>
                {{ /sections }}

                <div class="w-full flex justify-end mt-6">
                    <template x-if="processing === false">
                        {{ partial:components/button button_type="btn-primary" as="button" label="{send_action_label ?? 'Nachricht senden'}" }}
                            {{ slot:attributes }} @click.prevent="submit" {{ /slot:attributes }}
                        {{ /partial:components/button }}
                    </template>
                    <template x-if="processing === true">
                        {{ partial:components/button button_type="btn-primary" class="w-full !text-center opacity-75 cursor-default" as="button" label="{ partial:components/loading_circle } Bitte warten" }}
                            {{ slot:attributes }} @click.prevent="submit" disabled {{ /slot:attributes }}
                        {{ /partial:components/button }}
                    </template>
                </div>

                <template x-if="form.hasErrors">
                    <div id="summary" role="group" class="rounded border p-4 bg-red-50 border-red-700 mt-6">
                        <p class="leading-5 text-red-700">Bitte fülle die markierten Felder aus.</p>
                    </div>
                </template>
            </div>

            {{ if success_action == 'notification' }}
                <div id="summary" role="group" class="rounded p-6 mt-6 text-lg text-center leading-6" x-show="success" x-cloak x-transition>
                    {{ success_notification }}
                </div>
            {{ /if }}
        </div>
    {{ /form:create }}

    {{ partial:snippets/form_handler }}
{{ /if }}

@duncanmcclean
Copy link
Member

Can you try the fix @ryanmitchell suggested?

@MrMooky
Copy link
Sponsor Author

MrMooky commented May 14, 2024

@ryanmitchell That worked perfectly, thank you very much. :)

@MrMooky MrMooky closed this as completed May 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants