getgrav / getgrav/grav-plugin-form
Form cannot be sent if a "file" type field is required
- Dominant language
- PHP
- Stars
- 64
- Forks
- 80
- Avg merge
- 10h 13m
- Merged PRs (30d)
- 9
Description
Hi,
I have created a form that has a file type field and I need this field to be `required` but when I submit the form I get this error in console:
> An invalid form control with name='' is not focusable.
After performing searches, a `hidden` field may not be `required` (which makes sense in itself).
I looked at the `/plugins/form/app/fields/file.js` file and I think that no verification is done if `required` is `true` in the markdown file (where the form is defined).
So from what I understand, a `hidden` field of type hidden is added (by Dropzone ?).
To work around the problem, I would like to retrieve `this.dropzone` variable to check if there are files that have been added to the form, but I cannot access them (Using the given functions by Dropzone : https://stackoverflow.com/a/21221321).
Markdown:
```
form:
cv_lm:
label: false
type: file
display_label: false
destination: user/data/cv_lm
random_name: true
accept:
- application/pdf
- application/msword
- application/vnd.ms-fontobject
- application/vnd.oasis.opendocument.text
- application/vnd.openxmlformats-officedocument.wordprocessingml.document
limit: 5
multiple: true
name: cv_lm
validate:
required: false
message: Vous devez ajouter un CV et une lettre de motivation
buttons:
submit:
type: submit
value: Envoyer
classes: btn-form
process:
save:
fileprefix: candidature-
dateformat: Ymd-His-u
extension: txt
body: '{% include ''forms/data.txt.twig'' %}'
email:
to: '{{ config.plugins.email.to }}'
from: '{{ config.plugins.email.from }}'
subject: '[Formulaire de candidature] {{ form.value.name|e }} {{ form.value.email|e }}'
body: '{% include ''forms/data.html.twig'' %}'
content_type: text/html
charset: UTF-8
attachments:
- cv_lm
- other_files
message: 'Votre demande a bien été envoyée'
display: thankyou
```
HTML:
```
Formulaire de candidature
Nous ferons notre possible pour répondre dans les plus brefs délais
{% include "forms/recrutement.html.twig" %}
```
Include:
```
{% if form is null %}
{% set form = grav.session.getFlashObject('form') %}
{% endif %}
{% include 'partials/form-messages.html.twig' %}
{% set scope = scope ?: form.scope is defined ? form.scope : 'data.' %}
{% set multipart = '' %}
{% set blueprints = blueprints ?? form.blueprint() %}
{% set method = form.method|upper|default('POST') %}
{% set client_side_validation = form.client_side_validation is not null ? form.client_side_validation : config.plugins.form.client_side_validation|default(true) %}
{% set inline_errors = form.inline_errors is not null ? form.inline_errors : config.plugins.form.inline_errors(false) %}
{% set data = data ?? form.data %}
{% set context = context ?? data %}
{% for field in form.fields %}
{% if (method == 'POST' and field.type == 'file') %}
{% set multipart = ' enctype="multipart/form-data"' %}
{% endif %}
{% endfor %}
{% set action = form.action ?: page.route ~ uri.params %}
{% set action = (action starts with 'http') or (action starts with '#') ? action : base_url ~ action %}
{% if (action == base_url_relative) %}
{% set action = base_url_relative ~ '/' ~ page.slug %}
{% endif %}
{% if form.keep_alive %}
{% if grav.browser.browser == 'msie' and grav.browser.version < 12 %}
{% do assets.addJs('plugin://form/assets/object.assign.polyfill.js') %}
{% endif %}
{% do assets.addJs('plugin://form/assets/form.vendor.js', { 'group': 'bottom', 'loading': 'defer' }) %}
{% do assets.addJs('plugin://form/assets/form.min.js', { 'group': 'bottom', 'loading': 'defer' }) %}
{% endif %}
{% do assets.addInlineJs("
window.GravForm = window.GravForm || {};
window.GravForm.config = {
current_url: '" ~ uri.route(true) ~"',
base_url_relative: '" ~ base_url_relative ~ "',
param_sep: '"~ config.system.param_sep ~ "',
form_nonce: '" ~ form.getNonce() ~ "',
session_timeout: " ~ config.system.session.timeout ~ "
};
window.GravForm.translations = Object.assign({}, window.GravForm.translations || {}, { PLUGIN_FORM: {} });
", {'group': 'bottom', 'position': 'before'}) %}
{# Backwards Compatibility for block overrides #}
{% set override_form_classes %}
{% block form_classes -%}
{{ form_outer_classes }} {{ form.classes }}
{%- endblock %}
{% endset %}
{% set override_inner_markup_fields_start %}
{% block inner_markup_fields_start %}{% endblock %}
{% endset %}
{% set override_inner_markup_fields_end %}
{% block inner_markup_fields_end %}{% endblock %}
{% endset %}
{% set override_inner_markup_fields %}
{% block inner_markup_fields %}
{% for field_name, field in form.fields %}
{% set field_name = field.name ?? field_name %}
{% if field_name and not field.validate.ignore %}
{%- if field_name starts with '.' -%}
{% set field_name = field_name[1:] %}
{% set field = field|merge({ name: field_name }) %}
{% endif %}
{% set value = form ? form.value(field_name) : data.value(field_name) %}
{% block inner_markup_field_open %}{% endblock %}
{% block field %}
{% include "forms/fields/#{field.type}/#{field.type}.html.twig" ignore missing %}
{% endblock %}
{% block inner_markup_field_close %}{% endblock %}
{% endif %}
{% endfor %}
{% endblock %}
{% endset %}
{% set override_inner_markup_buttons_start %}
{% block inner_markup_buttons_start %}
{% endblock %}
{% endset %}
{# Embed for HTML layout #}
{% embed 'forms/layouts/form.html.twig' %}
{% block embed_form_core %}
name="{{ form.name }}"
action="{{ action | trim('/', 'right') }}"
method="{{ method }}"{{ multipart|raw }}
{% if form.id %}id="{{ form.id }}"{% endif %}
{% if form.novalidate %}novalidate{% endif %}
{% if form.keep_alive %}data-grav-keepalive="true"{% endif %}
{% endblock %}
{% block embed_form_classes -%}
class="{{ parent() }} {{ override_form_classes|trim }}"
{%- endblock %}
{% block embed_fields %}
{{ override_inner_markup_fields_start|raw }}
{{ override_inner_markup_fields|raw }}
{% include "forms/fields/formname/formname.html.twig" %}
{% include "forms/fields/formtask/formtask.html.twig" %}
{% include 'forms/fields/uniqueid/uniqueid.html.twig' %}
{{ nonce_field(form.getNonceAction() ?? 'form', form.getNonceName() ?? 'form-nonce')|raw }}
{{ override_inner_markup_fields_end|raw }}
{% endblock %}
{% block embed_buttons %}
{{ override_inner_markup_buttons_start|raw }}
{% for button in form.buttons %}
{% if button.outerclasses is defined %}
{% endfor %}
{{ override_inner_markup_buttons_end }}
{% endblock %}
{% endembed %}
{% if config.forms.dropzone.enabled %}
{% include 'forms/dropzone/template.html.twig' %}
{% endif %}
```
How can I get my form required?
Thank you
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with /plugins/form/app/fields/file.js and trace how the file field renders required validation alongside the Dropzone hidden field. Check the related form field templates and browser behavior, then verify that a required file field can be submitted with a file and does not trigger the non-focusable-control error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, php
- Domain
- frontend, web-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100