Form errors displayed twice - php

I've got a form to change a user password.
When the passwords aren't the same, the error message is displayed twice.
This is my code :
<div class="input-icon">
<i class="fa fa-lock"></i>
{{ form_widget(form.currentPassword, {'attr':{'type': 'text', 'class': 'form-control placeholder-no-fix', 'autocomplete': 'off', 'placeholder': 'sylius.form.user_change_password.current'|trans, 'name': 'current'}} ) }}
{{ form_errors(form.currentPassword) }}
</div>
And this is the result
The theme :
{%- block form_errors -%}
{%- if errors|length > 0 -%}
{%- for error in errors -%}
<div class="ui red {% if form.parent is not empty %}pointing {% endif %}label sylius-validation-error"{% if form.parent is empty %} style="margin-bottom: 10px;"{% endif %}>
{{ error.message }}
</div>
{%- endfor -%}
{%- endif -%}
{%- endblock form_errors -%}

Related

Symfony bootstrap theme

How to change default order of symfony form components?
I would like to have following order:
{{ form_label(form) }}
{{ form_widget(form) }}
{{ form_help(form) }}
{{ form_errors(form) }}
Currently is:
{{ form_errors(form) }}
{{ form_label(form) }}
{{ form_widget(form) }}
{{ form_help(form) }}
I have tried to modify this file: vendor/symfony/twig-bridge/Resources/views/Form/bootstrap_4_layout.html.twig:
...
{% block form_label -%}
{% if label is same as(false) -%}
{%- if errors|length > 0 -%}
<div id="{{ id }}_errors" class="mb-2">
{{- form_errors(form) -}}
</div>
{%- endif -%}
{%- else -%}
{%- if compound is defined and compound -%}
{%- set element = 'legend' -%}
{%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' col-form-label')|trim}) -%}
{%- else -%}
{%- set label_attr = label_attr|merge({for: id}) -%}
{%- endif -%}
{% if required -%}
{% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) %}
{%- endif -%}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<{{ element|default('label') }}{% if label_attr %}{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}{% endif %}>{{ translation_domain is same as(false) ? label : label|trans(label_translation_parameters, translation_domain) }}{% block form_label_errors %}{{- form_errors(form) -}}{% endblock form_label_errors %}</{{ element|default('label') }}>
{%- endif -%}
{%- endblock form_label %}
...
But without any success.
As you can see I have changed the order and put the errors in the first place, but still, it does not work and display an error in the first position.
First, you need to create a custom form theme for this, as outlined in the docs:
# config/packages/twig.yaml
twig:
form_themes: ['app_form_layout.html.twig']
Within app_form_layout.html.twig, we're going to override a couple of blocks to move the errors in the correct position:
We need to remove the default form_error(form) call from the form_label block, otherwise you'll end up with the form error being visible in two places.
We need to move that call to form_widget (which is a level up in the form template hierarchy tree)
Untested code example:
{% use "bootstrap_4_layout.html.twig" %}
{# this is basically the default form_label block, but with the form_error block definition removed, see line 260 of bootstrap_4_layout.html.twig #}
{% block form_label -%}
{# I think you can safely remove this if-statement, you currently might end up with 2 errors when you have a form with no label defined. #}
{% if label is not same as(false) -%}
{%- if compound is defined and compound -%}
{%- set element = 'legend' -%}
{%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' col-form-label')|trim}) -%}
{%- else -%}
{%- set label_attr = label_attr|merge({for: id}) -%}
{%- endif -%}
{% if required -%}
{% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) %}
{%- endif -%}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<{{ element|default('label') }}{% if label_attr %}{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}{% endif %}>
{%- if translation_domain is same as(false) -%}
{%- if label_html is same as(false) -%}
{{- label -}}
{%- else -%}
{{- label|raw -}}
{%- endif -%}
{%- else -%}
{%- if label_html is same as(false) -%}
{{- label|trans(label_translation_parameters, translation_domain) -}}
{%- else -%}
{{- label|trans(label_translation_parameters, translation_domain)|raw -}}
{%- endif -%}
{%- endif -%}
{# here was the form_errors call which is now gone #}</{{ element|default('label') }}>
{%- else -%}
{%- if errors|length > 0 -%}
<div id="{{ id }}_errors" class="mb-2">
{{- form_errors(form) -}}
</div>
{%- endif -%}
{%- endif -%}
{%- endblock form_label %}
{# here, we're adding the form_errors(form) call we just removed from the form_label block, so the error is in the correct position #}
{% block form_row -%}
{%- if compound is defined and compound -%}
{%- set element = 'fieldset' -%}
{%- endif -%}
{%- set widget_attr = {} -%}
{%- if help is not empty -%}
{%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%}
{%- endif -%}
<{{ element|default('div') }}{% with {attr: row_attr|merge({class: (row_attr.class|default('') ~ ' form-group')|trim})} %}{{ block('attributes') }}{% endwith %}>
{{- form_label(form) -}}
{{- form_widget(form, widget_attr) -}}
{{- form_help(form) -}}
{{- form_errors(form) -}} {# << here :-) #}
</{{ element|default('div') }}>
{%- endblock form_row %}

is there a way to add violation to multiple paths in symfony2?

is it possible to add a violation to multiple paths? like:
$this->context->buildViolation($constraint->message)
->atPath('initialDate')
->atPath('finalDate')
->addViolation();
it only add to initialDate.
You can still add two violations with an empty message on the second
$this->context->buildViolation($constraint->message)
->atPath('phone')
->addViolation()
;
$this->context->buildViolation('')
->atPath('email')
->addViolation()
;
but you will have the error markup generated also in the second field
You can also override the form_errors block to adjust the markup if no message
{% block form_errors -%}
{% if errors|length > 0 -%}
{% if form.parent %}<span class="help-block">
{% else %}<div class="alert alert-danger">{% endif %}
<ul class="list-unstyled text-danger">
{%- for error in errors if error.message -%}
<li><span class="glyphicon glyphicon-exclamation-sign"></span>
{{ error.message }}
</li>
{%- endfor -%}
</ul>
{% if form.parent %}</span>{% else %}</div>{% endif %}
{%- endif %}
{%- endblock form_errors %}

Twig - Symfony radio expanded not rendered correctly

I have a form twig template with helpers and form blocks which I want to use to automatically style my form in the way Zurb Foundations expects.
It seems to be working well mostly but I have run into an issue with choice expanded (radio buttons) as you can see below.
Here is the generate markup:
<div class="large-12 columns">
<input type="radio" id="user_gender_0" name="user[gender]" required="required" class="" value="male"> <label class="is-required">Male<input type="radio" id="user_gender_1" name="user[gender]" required="required" class="" value="female"> <label class="is-required">Female</label></label>
</div>
For some reason the label for the "Male" option is wrapping the "Female" option and when corrected in inspect element it's fine.
Here is my twig template where I override blocks:
{#
############# Radio #############
#}
{%- block radio_widget -%}
<input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />
{%- endblock radio_widget -%}
{#
############# Labels #############
#}
{%- block form_label -%}
{% if label is not sameas(false) -%}
{% if required -%}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' is-required')|trim}) %}
{%- endif %}
{% if errors|length > 0 -%}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' error')|trim}) %}
{% endif %}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}
{%- endif -%}
{%- endblock form_label -%}
{%- block button_label -%}{%- endblock -%}
Updated info, the form type option:
->add('gender', 'choice', [
'constraints' => new NotBlank(),
'choices' => Profile::getGenderTypes(),
'expanded' => true,
'multiple' => false,
'mapped' => false,
'attr' => [
'data-user-form' => 'gender'
]
])
Can anyone suggest a better layout to match Foundation 5 Forms.
Kindest Regards
Nathan
In this line
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}
You didn't close the label tag. That's why the Male label is wrapping the Female option.
Solution
Add </label> at the end.
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}</label>

Symfony2 errors on form field and parent

Is it possible to have validation on the form but keep it on the field at that same time? I am trying to have all my errors display at the top of the page but I would also like to have a red border around the error field. Also, each of my errors on the top should have a link that gives focus on the field that has that error.
If I use {{ form_errors(form.title) }}, I don't access to {{ form_errors(form) }}. If I use error_bubbling => true on the field then I don't access to {{ form_errors(form.title) }}. I was thinking of building my errors display in my controller, but if I do that, I'm losing Twig's functionality.
Customize your form_row block to not display error
{% block form_row %}
<div class="form-group{% if errors|length == 1 %} has-error{% endif %}">
{{ form_label(form, label|default(null)) }}
{{ form_widget(form, { 'attr' : { 'class' : 'form-control' } } ) }}
</div>
{% endblock form_row %}
Customize form_errors to be clickable. You can create a jQuery function to listen for clicks on li. In the function get the id of the clicked li remove RelatedField to get the field id
{% block form_errors -%}
{% if errors|length > 0 -%}
<ul id="allErrors">
{%- for error in errors -%}
<li id="RelatedField{{ error.id }}">{{ error.message }}</a></li>
{%- endfor -%}
</ul>
{%- endif %}
{%- endblock form_errors %}
References
How to Customize Form Rendering - http://symfony.com/doc/current/cookbook/form/form_customization.html
Here is the solution that I'm currenly using, I don't know if it's a good one. Personnaly I would rather do it all in Twig but I couldn't find a better way.
DefaultController.php : I'm passing the $errors to my view.
$errors = array();
if ($request->getMethod() == 'POST') {
$form->bind($this->getRequest());
if ($form->isValid()) {
...
} else {
foreach ($form->all() as $child) {
if (!$child->isValid()) {
$errors[$form->getName().'_'.$child->getName()] = substr($child->getErrorsAsString(),7);
}
}
}
}
template.html.twig
{% if errors|length > 0 %}
<ul>
{% for key, error in errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %} {% if errors|length > 0 %}class="error"{% endif %} />
{% endspaceless %}
{% endblock form_widget_simple %}
script.js
$('.errorClick').click(function() {
$('#'+$(this).attr('data-id')).focus();
});

How to apply a template to one form in Symfony2?

Page has two forms:
<div class="row">
<div class="col-lg-6">
{{ form(form) }}
</div>
</div>
<div class="row">
<div class="col-lg-6">
{{ form(user) }}
</div>
</div>
I set a theme for the form
{% form_theme form 'AcmeDemoBundle:Form:fields.html.twig' %}
But the theme is applied to both forms
My theme
{% block form_row -%}
<div class="form-group">
{{- form_label(form) -}}
{{- form_errors(form) -}}
{{- form_widget(form, { 'attr' :{ 'class' : 'form-control' }}) -}}
</div>
{%- endblock form_row %}
{% block button_row -%}
{{- form_widget(form, { 'attr' : { 'class': 'btn btn-default' }}) -}}
{%- endblock button_row %}
But I need to theme applies only to form

Categories