Adding html code in radio label - php

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

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 %}

Symfony 3.2 Form Field - Disabling the ID

Is it possible to render an input field without id?
I would like to disable it in the twig file.
I want that because I have a error "non-unique id" in the chrome console.
I have conducted research using the Symfony's documentation and I have found something that should work: "Customizing Form Output all in a Single File with Twig"
The block I want to replace is
{%- block widget_attributes -%}
This block is inside of the form_div_layout.twig.html
I put this inside of my_form.twig.html
{% form_theme form _self %}
{% block form_row %}
{%- block widget_attributes -%}
id="{{ id }}" name="{{ full_name }}"
{%- if disabled %} disabled="disabled"{% endif -%}
{%- if required %} required="required"{% endif -%}
{%- for attrname, attrvalue in attr -%}
{{- " " -}}
{%- if attrname in ['placeholder', 'title'] -%}
{{- attrname }}="{{ translation_domain is same as(false) ? attrvalue : attrvalue|trans({}, translation_domain) }}"
{%- elseif attrvalue is same as(true) -%}
{{- attrname }}="{{ attrname }}"
{%- elseif attrvalue is not same as(false) -%}
{{- attrname }}="{{ attrvalue }}"
{%- endif -%}
{%- endfor -%}
{%- endblock widget_attributes -%}
{% endblock form_row %}
{{ form_start(form) }}
......
And I get the error:
"Variable "full_name" does not exist. "
I don't want to edit the form_div_layout.html.twig
I did it!
For now, I think I found the solution
{% form_theme form _self %}
{% block form_row %}
{% block input_widget %}
{% set id = random() %} {# Random number for the id #}
{{ block('form_widget') }}
{% endblock input_widget %}
{% endblock form_row %}
{{ form_row(form.my_form) }}
This is not the final solution because I want the "id" not to show in the input form.

How to custom HTML form_errors in Symfony

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

Customizing Symfony form label based on targeted field type

I am trying to customize Symfony form label to add an asterisk(*) for all required fields through this Symfony doc. But my asterisk <span has to be inside the <label tag so I had to customize form_label block as described here. So far is good, but the customization also being applied to each item(label) of checkbox/radio fields. where it looks odd.
Any idea, how could I filter it in label customized block to format only for parent labels.
Here is my overridden code :
{% block form_label -%}
{% if label is not sameas(false) -%}
{% if not compound -%}
{% 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 -%}
{% set label = name|humanize %}
{%- endif -%}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{ label|trans({}, translation_domain) }}
{% if required %} <span class="required" title="This field is required">*</span> {% endif %}
</label>
{%- endif %}
{%- endblock form_label %}
In brief, I want a variable inside this block to identify the field type this label is targeting to.
Well, I resolved this with some tweak from the variable available in this overridden block.
Below is my overridden code for condition
{% if (required) and ( form.vars.checked is not defined ) %}
<span class="validation-error-star" title="This field is required">*</span>
{% endif %}
Instead of only required variable as condition, I further added another condition if there is any checked attribute defined for this field; which normally a radio/checkbox field type has.
This helped me to differentiate the field type inside a label overridden block. hope this helps somebody. :)

How to move "current" flag from <li> to <a> object in knpMenuBundle?

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;
}

Categories