Disable birthdate choice field - symfony

I have a form with a field for entering birthdate.
$builder->add('birthDate', 'birthday', array('label' => 'birthDate', 'translation_domain' => 'messages', 'required' => false, 'widget' => 'choice'))
In some cases i want to disable the birhtdate modifications in twig template, like.
{{ form_row(form.birthDate.day, {'attr': {'disabled': true}}) }}
{{ form_row(form.birthDate.month, {'attr': {'disabled': true}}) }}
{{ form_row(form.birthDate.year, {'attr': {'disabled': true}}) }}
This works fine, but if i render the complete row in one statement like:
{{ form_row(form.birthDate, {'attr': {'disabled': true}}) }}
This don't disable the birthdate field. Have anyone the same issue?
I solve my issue, the problem is that the attributes not injected into date_widget
I ovewrite the date_widget, now everything is fine.
Before i modify it:
{% block date_widget -%}
{% if widget == 'single_text' %}
{{- block('form_widget_simple') -}}
{% else -%}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) -%}
{% if datetime is not defined or not datetime -%}
<div {{ block('widget_container_attributes') -}}>
{%- endif %}
{{- date_pattern|replace({
'{{ year }}': form_widget(form.year),
'{{ month }}': form_widget(form.month),
'{{ day }}': form_widget(form.day),
})|raw -}}
{% if datetime is not defined or not datetime -%}
</div>
{%- endif -%}
{% endif %}
{%- endblock date_widget %}
After my modification
{% block date_widget -%}
{% if widget == 'single_text' %}
{{- block('form_widget_simple') -}}
{% else -%}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) -%}
{% if datetime is not defined or not datetime -%}
<div {{ block('widget_container_attributes') -}}>
{%- endif %}
{{- date_pattern|replace({
'{{ year }}': form_widget(form.year, {'attr': attr}),
'{{ month }}': form_widget(form.month, {'attr': attr}),
'{{ day }}': form_widget(form.day, {'attr': attr}),
})|raw -}}
{% if datetime is not defined or not datetime -%}
</div>
{%- endif -%}
{% endif %}
{%- endblock date_widget %}

You should not disable it in your template, but when you build your form. (see birthday form reference)

Maybe try widget instead of row:
{{ form_widget(form.birthDate.day, {'attr': {'disabled': true}}) }}

Related

Passing attr.class into the form theme in symfony 5

My form theme:
{% block form_row %}
<div class="form_row {% if errors|length > 0 %} is_error {% endif %} {{ attr.class }}" {% if attr|length > 0 %} {% for key, value in attr %} {{key}}="{{value}}" {% endfor %} {% endif %}>
{% if block_prefixes.1 != "checkbox" %}
{{ form_label(form)|raw }}
{% endif %}
{% if icon != null and block_prefixes.1 != "checkbox" %}
<div class="input__icon-container {% if block_prefixes.2 == "password" %}input__password-container{% endif %}">
<div class="icon">
{{ source('#public_path' ~ asset('build/images/icons/' ~ icon|replace({"icon-":""}) ~ '.svg')) }}
</div>
{% if block_prefixes.2 == "password" %}
<span class="password-reveal">Show</span>
{% endif %}
{{ form_widget(form, { 'attr': {'class': 'form-control'} }) }}
</div>
{{ form_errors(form) }}
{% else %}
{% if block_prefixes.2 == "password" %}
<div class="input__password-container">
<span class="password-reveal">Show</span>
{% endif %}
{{ form_widget(form, { 'attr': {'class': 'form-control'} }) }}
{% if block_prefixes.2 == "password" %}
</div>
{% endif %}
{{ form_errors(form) }}
{% endif %}
</div>
{% endblock %}
{% block radio_widget %}
<div class="label">{{ label|raw }} {% if help != null %} <span class="help">{{help}}</span> {% endif %}</div>
{% for choice in choices %}
<div class='input__choice-container'>
<label class="is_regular"> <input type="radio" name="{{ full_name}}" {% if required == "true" %} required="required" {% endif %} value="{{ choice.value }}"><span class="radio"></span> <span>{{ choice.label }}</span> </label>
</div>
{% endfor %}
{% endblock %}
{% block checkbox_widget %}
<div class="custom-checkbox custom-control">
<input type="checkbox" class="custom-control-input" id="{{id}}" name="{{ full_name}}">
<label class="custom-control-label" for="{{id}}">{{label|raw}}</label>
</div>
{% endblock %}
The error I got:
Key "class" does not exist as the array is empty.
But that's not accurate because this is my form output for this form row:
{{ form_row(registrationForm.displayname, {
attr : { "class" : "mb-1", "data-test" : "tests"}
})}}
So the question is here, how do I output the class content in the appropriate manner? Clearly I'm doing it wrong.
It is because your template doesnt print class literally
Understand the structure of forms here Form Customization
You will need to inject attribute print logic just like one of the built-in templates found( bootstrap 4 example) in Form Themes
{% block form_row -%}
{%- set widget_attr = {} -%}
{%- if help is not empty -%}
{%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%}
{%- endif -%}
<div{% with {attr: row_attr|merge({class: (row_attr.class|default('') ~ ' form-group' ~ ((not compound or force_error|default(false)) and not valid ? ' has-error'))|trim})} %}
{{ block('attributes') }}
{% endwith %}>
{{- form_label(form) }} {# -#}
{{ form_widget(form, widget_attr) }} {# -#}
{{- form_help(form) -}}
{{ form_errors(form) }} {# -#}
</div> {# -#}
{%- endblock form_row %}
If you don't want to do it over, extend built in form widgets which has the printing logic.
Or simply work out on your block to print these passed attributes.

Symfony 2 Form Theming Each Row?

I have been over the docs many times, but I can not seem to find a simple answer to my question. In my form, how do I apply a themed block to each row of my form, so that the right classes can be applied.
To explain, I currently have this in my twig template:
{% form_theme form 'XXBundle:Themes/floatRows.html.twig' %}
{{ form_start(form, {'attr': {'id': 'MyIDForm'}}) }}
{{ form_errors(form) }}
{{ form_row(form.row1) }}
{{ form_row(form.row2) }}
{{ form_row(form.row2) }}
{{ form_end(form) }}
In my theme file:
{% block form_row %}
<div class="ftLeft">
{%- if form.parent is empty -%}
{{ form_errors(form) }}
{%- endif -%}
{{- form_label(form) -}}
{{- form_widget(form) -}}
{{- form_errors(form) -}}
</div>
{% endblock %}
However what I am trying to do is this,
In my theme file I want,
{% block FloatLeft %}
<div class="ftLeft">
{%- if form.parent is empty -%}
{{ form_errors(form) }}
{%- endif -%}
{{- form_label(form) -}}
{{- form_widget(form) -}}
{{- form_errors(form) -}}
</div>
{% endblock %}
{% block FloatRight %}
<div class="ftRight">
{%- if form.parent is empty -%}
{{ form_errors(form) }}
{%- endif -%}
{{- form_label(form) -}}
{{- form_widget(form) -}}
{{- form_errors(form) -}}
</div>
{% endblock %}
Then to be able to apply each of these blocks to each row in turn (or wherever else I want them):
{{ form_start(form, {'attr': {'id': 'MyIDForm'}}) }}
{{ form_errors(form) }}
{{ form_row(form.row1) }} <-Block FloatLeft
{{ form_row(form.row2) }} <-Block FloatRight
{{ form_row(form.row2) }} <-No Block, no float class!
{{ form_end(form) }}
All help all ways welcome.
Thanks.
I used to have the same problem. I just solved it by extending twig with new simple functions. If you don't know how to go to this topic
Your function and your template must have the same name.

Customising form labels in Symfony

I have a symfony page where I display a form, and I would like to add an
* in the labels of all fields that are required.
So I have my form.php.twig, that looks like this:
{% extends "::layout.php.twig" %}
{% block body %}
<div class="row">
{% use 'form_div_layout.html.twig' with form_label as base_form_label %}
{% block form_label %}
{{ block('base_form_label') }}
{% if required %}
<span class="required" title="This field is required">*</span>
{% endif %}
{% endblock %}
</div>
{% endblock %}
I followed the exact documentation of the symfony cookbook on how to customise labels, which is http://symfony.com/doc/current/cookbook/form/form_customization.html#cookbook-form-theming-methods.
But I keep getting this error
Variable "label" does not exist in form_div_layout.html.twig at line 206
I don't have any label variable in the code of my form.php.twig so I don't see why I get this error. And when I remove the
{{ block('base_form_label') }}
I get
Variable "required" does not exist in ATPlatformBundle:Session:create.php.twig
Can anyone help me on this? I don't see where is my mistake? I am not looking to customise it with css, but to add the * .
I have checked the form_div_layout.html.twig at line 206 and this is what there is
{%- 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 -%}
{%- 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 %}>{{ translation_domain is sameas(false) ? label : label|trans({}, translation_domain) }}</label>
{%- endif -%}
{%- endblock form_label -%}
Thank you in advance.
Did you try defining the label from inside your form builder?! The below field is a required one because unless you mention required => false, your field will be rendered as required.
Something like:
->add('name', 'text', array('label' => '* name'))
With Twig, you should have to test the existence of a variable before using it:
Variable "required" does not exist
{% if required is defined and ... }
You need to test this because you field isn't always required.
if you want further information, you have this page of the documentation:
http://twig.sensiolabs.org/doc/tests/defined.html
Ok, so at the end, I didn't manage to change labels within my form.php.twig (which is the template I use to display my form), but I used another technique.
I created a new file named fields.php.twig, which I put in MyBundle/Resources/views/Form.
At the beginning of my fields.php.twig, I then added
{% extends 'form_div_layout.html.twig' %}
and below it, I added
{% block form_label %}
{{ parent() }}
{% if required %}
<span> * </span>
{% endif %}
{% endblock form_label %}
Then in my form.php.twig, I added
{% form_theme form 'MyBundle:Form:fields.php.twig' %}
{{ form_start(form) }}
Myform here with {{ form_label(form.property) }}
{{ form_errors(form.property) }}
{{ form_widget(form.property) }}
{{ form_end(form) }}
It works perfectly, but I had to create the fields.php.twig.

Symfony2 form entity style each option differently (collapse)

I have an entity field (visitors) in a form. I would like to highlight a person according to its status.
->add('visitors', 'entity', array(
'class' => "T2m3Bundle:Person",
'multiple' => true,
'property' => 'entireName',
'required' => false,
)
I have a method getStatus, that returns 4 states. On every state I want to put different "style" in an option tag.
Here is the example:
<select>
<option value="1">Mary</option>
<option value="2" class="alert alert-danger">John</option>
<option value="3" class="alert alert-success">Peter</option>
<option value="4" class="alert alert-warning">Robert</option>
</select>
So I want to do something like this:
{% for visitor in form.visitors %}
{% set index = visitor.vars.value %}
{% set entity = form.visitors.vars.choices[index].data %}
{% if entity.status == 1 %}
{{ form_widget(visitor) }}
<span class="alert alert-warning">{{ entity.entireName }}</span>
{% endif %}
{% if entity.status == 2 %}
{{ form_widget(visitor) }}
<span class="alert alert-danger">{{ entity.entireName }}</span>
{% endif %}
....
{% endfor %}
This example works for 'expanded' => true but not for collapse type. I would be really thankful for an answer.
Thanks in advance!
EDIT:
Expanded use this template with form_widget(...):
{% block choice_widget_expanded -%}
<div {{ block('widget_container_attributes') }}>
{%- for child in form %}
{{- form_widget(child) -}}
{{- form_label(child) -}}
{% endfor -%}
</div>
{% endblock choice_widget_expanded %}
but I don't know how to render manually collapsed type, where there is no {{- form_widget(...) -}}
Try to override the twig choice widget : refer to this link to find the according block. It's something like this
{% block choice_widget_collapsed -%}
{% if required and placeholder is none and not placeholder_in_choices and not multiple -%}
{% set required = false %}
{%- endif -%}
<select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
{% if placeholder is not none -%}
<option value=""{% if required and value is empty %} selected="selected"{% endif %}>{{ placeholder|trans({}, translation_domain) }}</option>
{%- endif %}
{%- if preferred_choices|length > 0 -%}
{% set options = preferred_choices %}
{{- block('choice_widget_options') -}}
{% if choices|length > 0 and separator is not none -%}
<option disabled="disabled">{{ separator }}</option>
{%- endif %}
{%- endif -%}
{% set options = choices -%}
{{- block('choice_widget_options') -}}
</select>
{%- endblock choice_widget_collapsed %}
{% block choice_widget_options -%}
{% for group_label, choice in options %}
{%- if choice is iterable -%}
<optgroup label="{{ group_label|trans({}, translation_domain) }}">
{% set options = choice %}
{{- block('choice_widget_options') -}}
</optgroup>
{%- else -%}
{# HERE we define the class based on the status #}
{% if status is defined %}
{% if status == 1 %}
{% set status_class = 'alert alert-warning' %}
{% elseif status == 2 %}
{% set status_class = 'alert alert-danger' %}
{% elseif ... %}
....
{% endif %}
{% endif %}
<option value="{{ choice.value }}"{% if choice is selectedchoice(value) %} selected="selected"{% endif %} {% if status_class is defined %} class="{{ status_class }}" {% endif %} >{{ choice.label|trans({}, translation_domain) }}</option>
{%- endif -%}
{% endfor %}
{%- endblock choice_widget_options %}
Finally in your template, call the widget like this :
{% for visitor in form.visitors %}
{% set index = visitor.vars.value %}
{% set entity = form.visitors.vars.choices[index].data %}
{{ form_widget(visitor, {'status': entity.status}) }}
....
{% endfor %}
This is not tested, but should work. Let me know.

Form theming datetime widget Symfony 2

I like to 'form-theme' my datetime widget in my form.
I have created a fields.html.twig file with this in it:
{% block datetime_widget %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{{ '{{ day }}-{{ month }}-{{ year }}'|replace({
'{{ day }}': form_widget(form.day),
'{{ month }}': form_widget(form.month),
'{{ year }}': form_widget(form.year),
})|raw }}
{{ form_widget(form.hour, { 'attr': { 'size': '1' } }) }} : {{ form_widget(form.minute, { 'attr': { 'size': '1' } }) }} : {{ form_widget(form.second, { 'attr': { 'size': '1' } }) }}
</div>
{% endspaceless %}
{% endblock datetime_widget %}
I've entered this line in my form view template
{% form_theme form 'AcmeDashboardBundle:Form:fields.html.twig' %}
The datetime widget gets rendered. But the date and time parts are in a separate div element. Which breaks the widget in 2 lines. I'd like to display the date and time part next to each other.
To achieve this you must redefine either the datetime_widget without using the built in date_widget & time_widget (because they are each wrapped with divs) or you can redefine the date_widget & time_widget to remove their wrapping divs.
Here's how to implement the first option:
{% extends 'form_div_layout.html.twig' %}
{% block datetime_widget %}
{% spaceless %}
{% if widget == 'single_text' %}1
{{ block('field_widget') }}
{% else %}
<div {{ block('widget_container_attributes') }}>
{{ form_errors(form.date.year) }}
{{ form_errors(form.date.month) }}
{{ form_errors(form.date.day) }}
{{ form_errors(form.time) }}
{{ form_widget(form.date.year) }}
{{ form_widget(form.date.month) }}
{{ form_widget(form.date.day) }}
{{ form_widget(form.time.hour, { 'attr': { 'size': '1' } }) }}:{{ form_widget(form.time.minute, { 'attr': { 'size': '1' } }) }}
</div>
{% endif %}
{% endspaceless %}
{% endblock datetime_widget %}
And here's how to implement the second option:
{% extends 'form_div_layout.html.twig' %}
{% block date_widget %}
{% spaceless %}
{% if widget == 'single_text' %}
{{ block('field_widget') }}
{% else %}
{{ date_pattern|replace({
'{{ year }}': form_widget(form.year),
'{{ month }}': form_widget(form.month),
'{{ day }}': form_widget(form.day),
})|raw }}
{% endif %}
{% endspaceless %}
{% endblock date_widget %}
{% block time_widget %}
{% spaceless %}
{% if widget == 'single_text' %}
{{ block('field_widget') }}
{% else %}
{{ form_widget(form.hour, { 'attr': { 'size': '1' } }) }}:{{ form_widget(form.minute, { 'attr': { 'size': '1' } }) }}{% if with_seconds %}:{{ form_widget(form.second, { 'attr': { 'size': '1' } }) }}{% endif %}
{% endif %}
{% endspaceless %}
{% endblock time_widget %}
Then the date & time will be together in the same div. Obviously you could add some space between the date and time by adding in your desired html
Hope that helps!

Resources