How to make 3 columns table with Twig in Symfony2 - symfony

I am new to Twig and Symfony2. I was wondering how can I create a 3 column table with Twig. My data comes from a database
So far I've tried everything but still nothin works. I found this on Stackoverflow about making a 2 column table, and it worked perfectly except for me. I want 3 columns .
<table>
{% for var in var1 %}
{% if (loop.index % 2) %}<tr>{% endif %}
<td>
<div class="bloc">
<a href="{{ path('xxxxxxx', {'id':var.id}) }}">
<span>{{ var.name}} </spann></a></div>
<img src="{{ asset(var.image ) }}" />
</div>
</td>
{% if (loop.index % 2) and loop.last %}
<td>&nbsp</td>
{% endif %}
{% if (loop.index0 % 2) or loop.last %}</tr>{% endif %}
{% endfor %}
</table>
ex: var1 contains names and pictures from database.
name1 name2 name3
name4 name5 name6
...
This is what I have ATM
name1 name2
name3 name4 name5
name6 name7 name8

My solution works for any number of columns:
{% set columns = 3 %}
{% for name in names %}
{% if loop.first or loop.index0 is divisibleby(columns) %}
<tr>
{% endif %}
<td>{{ name }}</td>
{% if loop.last and loop.index is not divisibleby(columns) %}
{% for n in range(low=columns - (loop.index % columns), high=1, step=-1) %}
<td> </td>
{% endfor %}
{% endif %}
{% if loop.last or loop.index is divisibleby(columns) %}
</tr>
{% endif %}
{% endfor %}

Correct way are you use batch (array_chunk):
{% for batchResults in result.items|batch(result.total_results / columns) %}
<div class="{{cycle(['left', 'left', 'right'], loop.index)}}">
{% for item in batchResults %}
<div class="{% if loop.last %}last{% endif %}">
{{item}}
</div>
{% endfor %}
</div>
{% endfor %}

Peekmo's solution is correct but there is possibly a neater way using the batch filter in twig. this filter breaks a list into smaller subsets. You control the size and use nested for loops to display rows and their contents. The example in the docs is an exact answer to this problem. The filter will also neatly handle empty cells. Ie you have 8 values in an array and you want a 3 column table, the last cell will be emtpy
http://twig.sensiolabs.org/doc/filters/batch.html

You should try something like that :
<table>
{% for var in var1%}
<tr>
<td>Title1<td>
<td>Title2<td>
<td>Title3<td>
</tr>
<tr>
<td>{{ var.attr1 }}<td>
<td>{{ var.attr2 }}<td>
<td>{{ var.attr3 }}<td>
</tr>
{%endfor%}
</table>

<table>
<tr>
{% for var in var1%}
{% if loop.index0 is divisibleby(3) %}
</tr>
<tr>
{% endif %}
<td>{{ var }}</td>
{% if loop.last %}
</tr>
{% endif %}
{%endfor%}
</table>
I think that could work for your problem, you have to open tag every 3 iterations, and do not forget to close the last one when your loop is terminated.

Untested, but should print a clean table.
<table>
{% for var in var1 %}
{% if not (loop.index0 % 3) %}<tr>{% endif %}
<td>
<div class="bloc">
<a href="{{ path('xxxxxxx', {'id':var.id}) }}">
<span>{{ var.name}} </spann></a></div>
<img src="{{ asset(var.image ) }}" />
</div>
</td>
{% if (loop.index % 2) and loop.last %}
<td>&nbsp</td>
{% endif %}
{% if (loop.index % 3) and loop.last %}
<td>&nbsp</td>
{% endif %}
{% if not (loop.index % 3) or loop.last %}</tr>{% endif %}
{% endfor %}
</table>

Related

Total dates with Twig

I found the difference between two dates and now I am trying to sum up all the differences. Can someone help me?
{% for clock in clock %}
{% set difference = date(clock.dateTimeStart).diff(clock.dateTimeEnd).format('%H:%I:%S') %}
<tr>
<td>{{ clock.dateTimeStart|date("d/m/Y") }}</td>
<td>{{ clock.dateTimeStart|date("H:i:s") }} to {{ clock.dateTimeEnd|date("H:i:s") }}</td>
<td>{{ difference }}</td>
</tr>
{% endfor %}
You can add DateTimeInterval's by adding them into a DateTime object and testing the difference at the end again.
{% set total_start = date('00:00') %}
{% set total_end = date('00:00') %}
{% for range in data %}
{% set difference = date(range.start).diff(date(range.end)) %}
{% do total_end.add(difference) %}
{{ difference.format('%H:%I:%S') }}
{% endfor %}
Total difference: {{ total_start.diff(total_end).format('%H:%I:%S') }}
demo

Dyanamic Variable names in Twig

For a series of similar named string how to I case them to a variable similar to php's $$variable ?
I have tried
{% for col in 1..cols %}
{% set field = 'field'~col %}
<td>
{{ form_widget(form.field) }}
</td>
{% endfor %}
But I get error property does not exist.
Solved it:
{% for col in 1..cols %}
{% set field = 'field'~col %}
<td>
{{ form_widget(attribute(form,field)) }}
</td>
{% endfor %}

Symfony2 layout composition or inheritance

I can't understand some principles about layout composition in sf2.
I have this App/Namespace/MyBundle/Resources/views/layout.html.twig template:
{% extends '::base.html.twig' %}
{% block title %}Main Title{% block subtitle %}{% endblock %}{% endblock %}
{% block head %}<h1>Placeholdertitle</h1>{% endblock %}
{% block body %}{% endblock %}
{% block sidebar %}{% endblock %}
How should I make the head.html.twig to replace the head block?
Currently I have this App/Bundle/Resources/views/head.html.twig template:
{% extends 'AppNamespaceMyBundle::layout.html.twig' %}
{% block head -%}
<h1>
Main Title
</h1>
{% endblock %}
Then I load a page with this index.html.twig:
{% extends 'AppNamespaceMyBundle::layout.html.twig' %}
{% block subtitle %} | Categories{% endblock %}
{% block body -%}
<h1>Categories list</h1>
<table class="records_list">
<thead>
<tr>
<th>Id</th>
<th>Text</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for entity in entities %}
<tr>
<td>{{ entity.id }}</td>
<td>{{ entity.text }}</td>
<td>
<ul>
<li>
show
</li>
<li>
edit
</li>
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<ul>
<li>
<a href="{{ path('category_new') }}">
Create a new entry
</a>
</li>
</ul>
{% endblock %}
And here I get the "Placeholdertitle" instead of the "Main Title", meaning that the head.html.twig isn't used. How am I supposed to use that head.html.twig to be in the layout.html.twig?
From what you are explaining, I guess that you want to render Layout + Head inside your Index.
You can use the following schema:
Layout <extended by> Head <extended by> Index. This way, when you will render Index, Twig will render both Head and Layout.
Another solution is to use the use.
PS: You cannot extends both head and layout in the same index file, as Twig says: Template inheritance is one of the most powerful Twig's feature but it is limited to single inheritance;
Did you try to remove the "-" in your head block in head.html.twig ?

count in twig without for loop

I want to total count resuslt. I have already done it like total group result and In total result in one product....
like:-
Total Group of Product = 15
In one group showing 36 product.
In second group showing 56 product.
I want to show total group product result = 36+56 => 92.
without for loop.
twig file:
<table>
<h2> Showing {{ templates | length }} Products</h2>
{% for groupResults in templates %}
{% if groupResults.doclist.docs[0].first_product_name is defined %}
Show all {{ groupResults | length }} results
<tr>
<td>
{{ groupResults.doclist.docs[0].first_product_name }}
{% if groupResults.doclist.numFound > 4 %}
Show all {{ groupResults.doclist.numFound }} results
{% endif %}
</td>
</tr>
<tr>
{% set count = 0 %}
{% for template in groupResults.doclist.docs %}
<td>
<a href="{{ path("customer_design_editor", { "templateSlug": template.slug, "productSlug": template.product_slug[0] }) }}">
<img src="{{ path("design_template_thumbnail_by_slug", { "slug": template.slug}) }}" alt="" />
</a>
</td>
{% set count = count + 1 %}
{% endfor %}
{% if count < 4 %}
{% for i in count..3 %}
<td> </td>
{% endfor %}
{% endif %}
{% else %}
{% endif %}
{% endfor %}
How about:
{% set totalCount = firstGroup|length + secondGroup|length %}

symfony2 form error vs field error theme (twig)

In Twig, is there a way to define a different theme for field errors as oppose to form related errors like CSRF error or composite unique constraints?
I want to display the field errors with a <span> and the form errors with a <ul>
{{ form_errors(form) }}
<table>
<tbody>
<tr>
<td>{{ form_label(form.tabla) }}</td>
<td>
{{ form_widget(form.tabla) }}
{{ form_errors(form.tabla) }}
</td>
<td></td>
<td>{{ form_label(form.descripcion) }}</td>
<td>
{{ form_widget(form.descripcion) }}
{{ form_errors(form.descripcion) }}
</td>
<td></td>
</tr>
</tbody>
</table>
This is my form theme that is being used for both cases (not what I want).
{% block field_errors %}
{% if errors|length > 0 %}
<span class="val-error">
{% for error in errors %}
{{ error.messageTemplate|trans(error.messageParameters, 'validators')~'. ' }}
{% endfor %}
</span>
{% endif %}
{% endblock field_errors %}
Is there a way to differentiate both cases?
Form class extends Field. If you set a new theme to field it will be applied to form.
You should override the field_errors block as you did, and then define the form_errors block using another template (with th ul tag).
{% block field_errors %}
{% if errors|length > 0 %}
<span class="val-error">
{% for error in errors %}
{{ error.messageTemplate|trans(error.messageParameters, 'validators')~'. ' }}
{% endfor %}
</span>
{% endif %}
{% endblock field_errors %}
{% block form_errors %}
{% if errors|length > 0 %}
<ul class="val-error">
{% for error in errors %}
<li>{{ error.messageTemplate|trans(error.messageParameters, 'validators')~'. ' }}</li>
{% endfor %}
</ul>
{% endif %}
{% endblock form_errors %}
Since field_* is removed in 2.3 the approved solution will no longer work. A hacky solution I have found is
{% block form_errors %}
{% if errors|length > 0 %}
{% if form.parent is empty %}
<ul class="val-error">
{% for error in errors %}
<li>{{ error.messageTemplate|trans(error.messageParameters, 'validators')~'. ' }}</li>
{% endfor %}
</ul>
{% else %}
<span class="val-error">
{% for error in errors %}
{{ error.messageTemplate|trans(error.messageParameters, 'validators')~'. ' }}
{% endfor %}
</span>
{% endif %}
{% endif %}
{% endblock form_errors %}
So basically what this does is if there is no parent, it knows it is the top level.

Resources