Hide day and month widgets in date form field - symfony

This does not hide the month and day widgets entirely...
{% block date_widget %}
{% spaceless %}
{% if widget == 'single_text' %}
{{ block('field_widget') }}
{% else %}
<div {{ block('widget_container_attributes') }}>
{{ date_pattern|replace({
'{{ year }}': form_widget(form.year),
'{{ month }}': form_widget(form.month, { 'attr' : { 'style': 'display:none' }}),
'{{ day }}': form_widget(form.day, { 'attr' : { 'style': 'display:none' }}),
})|raw }}
</div>
{% endif %}
{% endspaceless %}
{% endblock date_widget %}
...and this:
'{{ month }}': '',
'{{ day }}': '',
fails during validation.
Any ideas how we can remove day and month widgets from the date form field?

The date type without the month and day parts is just a year type. So, why don't you create one instead of misusing the type meant for dates?
You could use the choice type or create a year type based on it. You could also take a look at the years options of the birthday type and add a similar option to your new type.

Related

How to use this callback message in this function

I'm struggeling to select a previous for loop in Twig. I'm trying to display a few category titles in a category if that category has subcategories. If the category has no subcategories then it shhould display the titles from the previous loop. Normally this wouldn't be a problem if any category has the same depth. Unfortunatly the categories have different depths.
So what I try to do is create some sort of function that does this for me.
So for example:
Category A -> Category A.sub -> Category A.subsub
Title1 Title1.1 Title1.2
Title1 Title1.1 Title1.2
Category B -> Category B.sub -> Category A.subsub
Title1 Title1.1 Title1.1
Title1 Title1.1 Title1.1
As you can see Category B.sub.sub hasn't any subcategories. If that's the case it should show the subcategories from Category B.sub. Normally I would do something like this:
{% for category in shop.categories %}
{{ category.title }}
{% if category.subs %}
{% for category in category.subs %}
{{ category.title }}
{% if category.subs %}
{% for category in category.subs %}
{{ category.title }}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
Is there any way to create somesort of function that checks if a category has subcategories. If that's not the case the access the previous loop and display those category names.
I thought this was as simple as:
{% elseif not category.subs %}
{# Do this #}
But that's not the case :(
My suggestion is to make the structure of the arrays alike within your php code and don't put such kind of logic in the template.
So in php you wold have something like this:
if (!isset($categoryB['sub']['subsub']) {
$categoryB['sub']['subsub'] = $categoryA['sub']['subsub'];
}
and then your template you just iterate:
{% for category in shop.categories %}
{{ category.title }}
{% for category in category.subs %}
{{ category.title }}
{% for category in category.subs.subsub %}
{{ category.title }}
And I would also suggest to make it recursive so you would have something like:
{% itarerateCategoryes categories %}
Agreeing with Fyntasia I wouldn't have lots of logic in the template, I would parse the data in the controller to the form I wanted.
However assuming your data array is something like (couldn't understand your notation);
$categories = [
0 => [
'top' => ['Atop1', 'Atop2'],
'middle' => ['Amiddle1', 'Amiddle2'],
'bottom' => ['Abottom1', 'Abottom2'],
],
1 => [
'top' => ['Btop1', 'Btop2'],
'middle' => ['Bmiddle1', 'Bmiddle2'],
],
];
Something like;
{% for main_index, category in categories %}
{% if category.top is defined and category.top|length > 0 %}
{{ loop.index0 }} has top values
{% endif %}
{% if category.middle is defined and category.middle|length > 0 %}
{{ loop.index0 }} has middle values
{% endif %}
{% if category.bottom is defined and category.bottom|length > 0 %}
{{ loop.index0 }} has bottom values
{% else %}
{{ loop.index0 }} has no value so using {{ categories[loop.index0 - 1].bottom|join(', ') }}
{% endif %}
<br />
{% endfor %}
Outputs something like;
0 has top values 0 has middle values 0 has bottom values
1 has top values 1 has middle values 1 has no value so using Abottom1, Abottom2

Disable birthdate choice field

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

Twig - Why can't I access a variable I've set?

For some reason, a variable I'm setting in one form template bloc is not available in a child form block.
I have an 'entity' field type to present a selection of checkboxes to allow the user to select related items...
$builder
->add( 'title' )
->add(
'apps',
'entity',
[
'class' => 'OurAdminBundle:App',
'choices' => $apps,
'property' => 'title',
'expanded' => true,
'multiple' => true
]
)
And here's the template that renders the form
// Effectively imported using the MopaBootstrapBundle
// {% form_theme form 'OurAdminBundle:Form:fields.html.twig %}
// Further in page theming
{% form_theme form _self %}
// Set variable when on the apps field, so it should be available to all child
// forms
{% block _gallery_apps_widget %}
{% set custom_checkboxes = 1 %}
{{ block('choice_widget') }}
{% endblock %}
// Attempt to retrieve the variable on the checkboxes within the apps entity
/ field
{% block checkbox_widget %}
{{ dump(custom_checkboxes|default(0) }} // Displays 0
{% endblock checkbox_widget %}
Here's the code from the fields.html.twig file (with minor debugging additions...
{% block choice_widget_expanded %}
{{ dump(custom_checkboxes|default(0)) }}
{% set custom_checkboxes = custom_checkboxes|default(0) %}
{{ dump(custom_checkboxes|default(0)) }}
{% spaceless %}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default(''))}) %}
{% set label_attr = label_attr|merge({'class': (label_attr.class ~ ' ' ~ (widget_type != '' ? (multiple ? 'checkbox' : 'radio') ~ '-' ~ widget_type : ''))}) %}
{% if expanded %}
{% set attr = attr|merge({'class': attr.class|default(horizontal_input_wrapper_class)}) %}
{% endif %}
{% for child in form %}
{% if widget_type != 'inline' %}
<div class="{{ multiple ? 'checkbox' : 'radio' }}">
{% endif %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{ form_widget(child, {'horizontal_label_class': horizontal_label_class, 'horizontal_input_wrapper_class': horizontal_input_wrapper_class, 'attr': {'class': attr.widget_class|default('')}}) }}
{{ child.vars.label|trans({}, translation_domain) }}
</label>
{% if widget_type != 'inline' %}
</div>
{% endif %}
{% endfor %}
{% endspaceless %}
{% endblock choice_widget_expanded %}
... which successfully displays '1' on both counts.
I've racked my brains over this one, but can't for the life of me understand why I can't access the variable in the checkbox_widget block. Please help.
This is due to how Symfony renders form fields when calling form_widget() or any other form* family of functions.
Symfony creates a new separate scope which do not share the scope of the parent (in order to prevent scope polluting while rendering fields).
If you which to pass a variable to the checkbox widget, edit the form_widget call in the choice_widget_expanded to pass on the custom_checkboxes as so (added tabbing for clarity only):
{{ form_widget(child, {
'horizontal_label_class': horizontal_label_class,
'horizontal_input_wrapper_class': horizontal_input_wrapper_class,
'attr': {'class': attr.widget_class|default('')},
'custom_checkboxes': custom_checkboxes
}) }}

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!

Symfony2: Extending the twig date field

I would like to override the existing date field type so that I can use a js component.
I tried so far:
{% block date_widget %}
{% spaceless %}
<input type="text" {{ block('attributes') }} readonly="true" value="{{ value }}"/>
<script>
mycal = new dhtmlxCalendarObject("{{ id }}");
mycal.setSkin('yahoolike');
mycal.setDateFormat('%d.%m.%Y');
mycal.loadUserLanguage("de");
mycal.draw();
</script>
{% endspaceless %}
{% endblock date_widget %}
It doesn't work so far (the js component is shown, but with no function), my questions are: in value, I need the date representation as a string like '31.12.2011', but value seems to be an empty array.
Another question: how can twig/sf2 then recognize the result? The components writes the date as string in the input field, but sf gives me an error
Expected argument of type "array",
"string" given
I use Symfony 2.0, Beta 5
I succeeded - my error was that I forgot to specify the 'widget'-option as single text: 'widget' => 'single_text'.
Here is my FormBuilder:
$builder->add('abgabedatum', 'date', array('label' => 'Abgabedatum', 'widget' => 'single_text'));
and my entry in fields.html.twig (my form_theme)
{% block date_widget %}
{% spaceless %}
<input type="text" {{ block('attributes') }} readonly="true" value="{{ value }}"/>
<script>
mycal = new dhtmlxCalendarObject("{{ id }}");
mycal.setSkin('yahoolike');
mycal.setDateFormat('%d.%m.%Y');
mycal.loadUserLanguage("de");
mycal.draw();
</script>
{% endspaceless %}
{% endblock date_widget %}

Resources