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 %}
Related
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 -%}
I would like custom the render of form_errors in Symfony 3, because I would like obtain (in my Twig remplate) :
<div class="alert alert-danger">My error</div>
Instead of :
<ul><li>My error</li></ul>
It's possible ?
I tried this :
{{ form_errors(form.name) ? '<div class="alert alert-danger">' ~ form_errors(form.name) ~ '</div>' : '' }}
But the HTML is not interpreted and it may not be very clean ..
And this (Recovery of vendor\symfony\symfony\src\Symfony\Bridge\Twig\Resources\views\Form\form_div_layout.html.twig line 307):
I overloaded:
{%- block form_errors -%}
{%- if errors|length > 0 -%}
<ul>
{%- for error in errors -%}
<li>{{ error.message }}</li>
{%- endfor -%}
</ul>
{%- endif -%}
{%- endblock form_errors -%}
By :
{%- block form_errors -%}
{%- if errors|length > 0 -%}
<ul>
{%- for error in errors -%}
<li>{{ error.message }}</li>
{%- endfor -%}
</ul>
{%- endif -%}
{%- endblock form_errors -%}
But the variable "error" is not defined
Thanks in advance for your help
Take a look at this website:
https://symfonycasts.com/screencast/symfony-forms/form-theme-create#play
You need to modify below file
vendor/symfony/symfony/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig
and search for the {% block form_errors -%} block to modify it.
you can look here for more informations:
https://codereviewvideos.com/course/beginner-s-guide-to-symfony-3-forms/video/styling-and-customising-using-form-fragments
But this is not the right method, the good one is to override this file by copy that block into another twig template, modify it and call this template into the twig template of your page.
Here are the explanations:
https://symfonycasts.com/screencast/symfony-forms/form-theme-create#play
I am fighting with customize on symfony forms for twig...
My problem is to add html inside a label for a radio button like <strong>25</strong> but it is escaped by default and I can't find how to unescape. I use the following code.
{% block choice_widget %}
{%
set labels = {
1: { title: '1 ' ~ 'label.credits'|trans ~ ' - <strong>1€</strong>' },
2: { title: '2 ' ~ 'label.credits'|trans ~ ' - <strong>2€</strong>' },
25: { title: '25 ' ~ 'label.credits'|trans ~ ' - <strong>25€</strong>' },
}
%}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
{% if child.vars.value matches '/^[1|2|25]{1}/' %}
{% set currentLabel = labels[child.vars.value].title %}
{% else %}
{% set currentLabel = '' %}
{% endif %}
{{ form_widget(child, {'label': currentLabel}) }}
{{ form_label(child) }}
{{ form_errors(child) }}
{% endfor %}
</div>
{% endblock %}
In your case you will need to override the form_label block and incorporate into your own theme (https://symfony.com/doc/current/form/form_customization.html), this is for bootstrap 4 (find the file in vendors folder called bootstrap_4_layout.html.twig, if you need this for bootstrap 3 just do the same but the file is bootstrap_3_layout.html.twig), notice where I've inserted the <strong> and </strong> tags:
{% block form_label -%}
{% 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 %}><strong>{{ translation_domain is same as(false) ? label : label|trans({}, translation_domain) }}</strong>{% block form_label_errors %}{{- form_errors(form) -}}{% endblock form_label_errors %}</{{ element|default('label') }}>
{%- else -%}
{%- if errors|length > 0 -%}
<div id="{{ id }}_errors" class="mb-2">
{{- form_errors(form) -}}
</div>
{%- endif -%}
{%- endif -%}
{%- endblock form_label %}
You can try the above by putting it in the actual twig view and putting this statement above it:
{% form_theme form _self %}
Extra (for a checbkox): To achieve this for a checkbox you will need to override the label template, pull out the block for
{% block checkbox_radio_label -%} from bootstrap_4_layout.html.twig or bootstrap_3_layout.html.twig and then incorporate this into your own theme.
Extra extra (for a checkbox): If you also need to customise the widget, pull out the block for {% block checkbox_widget -%} i.e. remove the label rendering from within it (yes, for some internal reason the widget generates the label as well) and customise the way you want it to be. This way even calling form_label on a checkbox will output the label (otherwise form_label will not output anything)
Look here : http://symfony.com/doc/current/reference/forms/types/choice.html#select-tag-checkboxes-or-radio-buttons
You can put the parameter expanded to true and multiple to false in your formType for have radio buttons in your html
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();
});
I have been looking at this twig code for a while, and tried a few trix to move the flag of the "current" item down to the link object (a) instead of the list item object (li) but I can't seem to get it right.
The output I get at the moment is
<ul>
<li class="current first">
Hem
</li>
The desired output is
<ul>
<li class="first">
<a class="current" href="/hemekonomi/web/app_dev.php/">Hem</a>
</li>
Here is the twig file (the standard twig template file for knpMenuBundle with irrelevant modifications to it).
{% macro attributes(attributes) %}
{% for name, value in attributes %}
{%- if value is not none and value is not sameas(false) -%}
{{- ' %s="%s"'|format(name, value is sameas(true) ? name|e : value|e)|raw -}}
{%- endif -%}
{%- endfor -%}
{% endmacro %}
{% block compressed_root %}
{% spaceless %}
{{ block('root') }}
{% endspaceless %}
{% endblock %}
{% block root %}
{% set listAttributes = item.childrenAttributes %}
{{ block('list') -}}
{% endblock %}
{% block list %}
{% if item.hasChildren and options.depth is not sameas(0) and item.displayChildren %}
<ul class="art-hmenu">
{{ block('children') }}
</ul>
{% endif %}
{% endblock %}
{% block children %}
{# save current variables #}
{% set currentOptions = options %}
{% set currentItem = item %}
{# update the depth for children #}
{% if options.depth is not none %}
{% set options = currentOptions|merge({'depth': currentOptions.depth - 1}) %}
{% endif %}
{% for item in currentItem.children %}
{{ block('item') }}
{% endfor %}
{# restore current variables #}
{% set item = currentItem %}
{% set options = currentOptions %}
{% endblock %}
{% block item %}
{% if item.displayed %}
{# building the class of the item #}
{%- set classes = item.attribute('class') is not empty ? [item.attribute('class')] : [] %}
{%- if item.current %}
{%- set classes = classes|merge([options.currentClass]) %}
{% set aFlag = ' class="active"' %}
{%- elseif item.currentAncestor %}
{%- set classes = classes|merge([options.ancestorClass]) %}
{%- endif %}
{%- if item.actsLikeFirst %}
{%- set classes = classes|merge([options.firstClass]) %}
{%- endif %}
{%- if item.actsLikeLast %}
{%- set classes = classes|merge([options.lastClass]) %}
{%- endif %}
{%- set attributes = item.attributes %}
{%- if classes is not empty %}
{%- set attributes = attributes|merge({'class': classes|join(' ')}) %}
{%- endif %}
{# displaying the item #}
<li{{ _self.attributes(attributes) }}>
{%- if item.uri is not empty and (not item.current or options.currentAsLink) %}
{{ block('linkElement') }}
{%- else %}
{{ block('spanElement') }}
{%- endif %}
{# render the list of children#}
{%- set childrenClasses = item.childrenAttribute('class') is not empty ? [item.childrenAttribute('class')] : [] %}
{%- set childrenClasses = childrenClasses|merge(['menu_level_' ~ item.level]) %}
{%- set listAttributes = item.childrenAttributes|merge({'class': childrenClasses|join(' ') }) %}
{{ block('list') }}
</li>
{% endif %}
{% endblock %}
{% block linkElement %}<a href="{{ item.uri }}"{{ _self.attributes(item.linkAttributes) }}>{{ block('label') }}</a>{% endblock %}
{% block spanElement %}<span{{ _self.attributes(item.labelAttributes) }}>{{ block('label') }}</span>{% endblock %}
{% block label %}{% if options.allow_safe_labels and item.getExtra('safe_label', false) %}{{ item.label|raw }}{% else %}{{ item.label }}{% endif %}{% endblock %}
Instead of moving the "current" class, I drilled down to the desired object with this css:
ul.mainmenu>li.current > a > div {
opacity:0.6;
}