How can I use loop functionality in twig template? - symfony

I want to use a looping functionality in region.html.twig file to I can
wrap elements that outputted from {{ content }} section.
Defult region.html.twig
{% if content %}
<div class="Parent">
{{ content }}
</div>
{% endif %}
The schematic generated Output:
<div class="Parent">
Item_1
Item_2
Item_3
</div>
I try to use below code to create a loop and add a wrapper around of each Item outputted from {{ content }}:
My code:
{% if content %}
<div class="Parent">
{% for item in items %}
<div class="child-wrapper">{{ item.content }}</div>
{% endfor %}
</div>
{% endif %}
The Final outpute that I want to achive:
<div class="Parent">
<div class="child-wrapper">Item_1</div>
<div class="child-wrapper">Item_2</div>
<div class="child-wrapper">Item_3</div>
</div>

If your data is: content = [1, 2, 3, ... , 100]
Then write
{% if content %}
<div class="Parent">
{% for item in content %}
<div class="child-wrapper">{{ item }}</div>
{% endfor %}
</div>
{% endif %}
If your data is array of assotiated arrays like this:
content = [
['content' => 1],
['content' => 2],
]
Then write
{% if content %}
<div class="Parent">
{% for item in content %}
<div class="child-wrapper">{{ item.content }}</div>
{% endfor %}
</div>
{% endif %}

Related

grav modular page - separate content and sidebar

I want to create a page in grav, where I have a content area and a sidebar area.
I want to use on modular.md root template in which I refer to a template that loops and displays both content and sidebar modules.
My problem is: how to distinguish between content and sidebar?
my template looks like this:
{% block body %}
{% block content %}
<section id="info">
<div class="container">
<div class="row">
<div class="col-sm-12">
<div class="row">
<div class="col-sm-8">
<div id="content" class="site-content bg">
<h2 class="heading">{{ page.title }}</h2>
{{ page.content }}
{% for module in page.collection() %}
{{ module.content }}
{% endfor %}
</div>
</div>
<div id="sidebar" class="col-sm-4 sidebar-inner">
{% for module in page.collection() %}
{{ module.content }}
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
</section>
{% endblock %}
{% endblock %}
What I try to achieve is to use filters on both page.collections, so that in one case only "content" (taxonomy.tag was my guess here) and in the other case only sidebar is used.
I could live with naming conventions (sidebar modules have a fixed prefix), but I can't figure it out.
okay, I came along with a hack: I include 'sidebar' in the folder name of the module and filter on module.folder name. I am convinced there is a better solution, though!
<section id="info">
<div class="container">
<div class="row">
<div class="col-sm-12">
<div class="row">
<div class="col-sm-8">
{% if page.content %}
<div id="content" class="site-content bg">
<h2 class="heading">{{ page.title }}</h2>
{{ page.content }}
</div>
{% endif %}
{% for module in page.collection() %}
{% if 'sidebar' not in module.folder %}
{{ module.content }}
{% endif %}
{% endfor %}
</div>
<div id="sidebar" class="col-sm-4 sidebar-inner">
{% for module in page.collection() %}
{% if 'sidebar' in module.folder %}
{{ module.content }}
{% endif %}
{% endfor %}
</div>
</div>
</div>
</div>
</div>
What you can do (I think) is set a value in the fromtmatter of the module
sidebar: true
Then you can filter on that value in your collection like
{% for module in page.collection() %}
{% if page.header.sidebar %}
{{ module.content }}
{% endif %}
{% endfor %}

Text columns in front of form using {{form_label()}}

I am trying to reuse this old code to make some forms:
In a form.html.twig
<div class="row" style='margin-bottom: 5px'>
<div style='white-space:nowrap'>
<div class='col-xs-2'></div>
<div class='col-xs-3' style='border-bottom:1px solid black;padding-bottom: 14px'><div style='float:right'>{{ form_label(form.class.variable, 'Text on one column and text on another column', {'label_attr':{'style':'margin-top:5px'}})}}</div>
<div class='col-xs-3' style='border-bottom:1px solid black;padding-bottom: 5px'>{{ form_widget(form.class.variable, {'attr':{'style':'width:95px','placeholder':'RAW value'}})}}</div>
<div class='col-xs-3'></div>
</div>
I would like to have two columns before the form like on this picture:
Thank you for the hints!
You will need to customise your form_label block.
Have a look at the example here
EDIT:
Roughly, you're after something like this:
Your form theme (say, two_column_labels.html.twig):
{% extends 'form_div_layout.html.twig' %}
{% block form_row %}
<div class="row">
<div class="col-sm-6">
{{ form_label(form) }}
</div>
<div class="col-sm-3">
{{ form_errors(form) }}
</div>
<div class="col-sm-3">
{{ form_widget(form) }}
</div>
</div>
{% endblock form_row %}
{% block form_label %}
{% if label_attr.extra_label is defined %}
<div class="row">
<div class="col-sm-6">
{% set orig_label = label %}
{% set new_label_attr = [] %}
{% for key,value in label_attr %}
{% if key != 'extra_label' %}
{% set new_label_attr = new_label_attr|merge({(key): value}) %}
{% else %}
{% set label = value %}
{% endif %}
{% endfor %}
{% set label_attr = new_label_attr %}
{{ parent() }}
{% set label = orig_label %}
</div>
<div class="col-sm-6">
{{ parent() }}
</div>
</div>
{% else %}
{{ parent() }}
{% endif %}
{% endblock form_label %}
In your form field definition in your form class:
'label' => 'Second Label',
'label_attr' => array('extra_label' => 'First Label'),
In your form template:
{% form_theme form 'two_column_labels.html.twig' %}

How do I use the django template tag in the css tag?

I tried to use the forloop.last template tag
<div class="panel-body">
{% for card in cardlist.card_set.all %}
{% if forloop.last %}
<div class="well" style="margin-bottom: 0px;">{{ card.title }}</div>
{% else %}
<div class="well" style="margin-bottom: 20px;">{{ card.title }}</div>
{% endif %}
{% endfor %}
</div>
How do I refactor the above source like the source below?
In the refactored source, "margin-bottom: {{margin-bottom}} px;" Error in "{{margin-bottom}}".
<div class="panel-body">
{% for card in cardlist.card_set.all %}
{% if forloop.last %}
margin-bottom = 0
{% else %}
margin-bottom = 20
{% endif %}
<div class="well" style="margin-bottom: {{ }}px;">{{ card.title }}</div>
{% endfor %}
</div>
you can try it:
<div class="panel-body">
{% for card in cardlist.card_set.all %}
<div class="well" style="margin-bottom:{% if forloop.last %}0px{% else %}20px{% endif %};">{{ card.title }}</div>
{% endfor %}
</div>

symfony twig background image

I need to know why this script doesn't work with me and If anyone has a solution it will be appreciated.
My problem is that the image wouldn't be displayed background-image:url('{{asset('uploads/images/')}}{{image.name}}
<div class="carousel-inner">
{% set i = 0 %}
{% for project in projects %}
{% for image in project.images[:1] %}
{% if i == 0 %}
<div class="item active">
{% else %}
<div class="item">
{% endif %}
<div class="fill" style="background-image:url('{{asset('uploads/images/')}}{{image.name}}')"></div>
<div class="carousel-caption">
<h2>{{project.name}}</h2>
</div>
</div>
{% endfor %}
{% set i = i + 1 %}
{% endfor %}
</div>
</div>
You need to include your image.name inside of the asset() function.
{{asset('uploads/images/')}}{{image.name}} changed to
{{asset('uploads/images/' ~ image.name)}}

Twig batch with condition

I send Cards(some data) from controller to twig and create row with 3 elems.
{% for elem in Cards|batch(3) %}
<div>
<div class="row">
{% include ':appviews/elements/Card:Card.html.twig' with {'elem': elem} %}
</div>
</div>
{% endfor %}
It works well, but now i need to add card with static html (not from Data), that must be rendered one time.
Is there way, to add only 2 elems in row for the first loop?
{% for elem in Cards|batch(3) %}
<div>
<div class="row">
{% if loop.first %}
<div class="col-md-4 noPadding margin">
<div class="square"> SOME TEXT</div>
</div>
{% endif %}
{% include ':appviews/elements/Card:Card.html.twig' with {'elem': elem} %}
</div>
</div>
{% endfor %}
You cannot do this with "batch" filter. I suggest you use some logical tricks. There can be many of them, depending on:
how often do you want to insert the hardcoded block
how much code/template piece is being reused
For example, if you only need this once in the beginning, you can slice your array once, and then slice it again:
{% for elem in Cards|slice(0, 1) %}
<div>
<div class="row">
{% if loop.first %}
<div class="col-md-4 noPadding margin">
<div class="square"> SOME TEXT</div>
</div>
{% endif %}
{% include ':appviews/elements/Card:Card.html.twig' with {'elem': elem} %}
</div>
</div>
{% endfor %}
{% for elem in Cards|slice(2, Cards|length) %}
...
{% endfor %}
If you think there's too much copy/paste going on, you can create a macro for the "row", with some parameters and have all the logic in it. Then you can control, how, when and what is rendered. But this can be an overload in simple cases, so you decide:
http://twig.sensiolabs.org/doc/tags/macro.html
Well, final code is:
<div class="row rowQuest">
<div class="col-md-4 noPadding margin">
<div class="square">HARDCODED CARD</div>
</div>
{% set firstPartOfQuests = quests|slice(0,2) %}
{% for elem in firstPartOfQuests|batch(2) %}
{% include 'appviews/elements/questCard/questCard.html.twig' with {'elem': elem} %}
{% endfor %}
</div>
{% set lastPartOfQuests = quests|slice(2,quests|length) %}
{% for elem in lastPartOfQuests|batch(3) %}
<div class="row rowQuest">
{% include ':appviews/elements/questCard:questCard.html.twig' with {'elem': elem} %}
</div>
{% endfor %}
PS i still don't understand why i can't use for cycle without batch.
{% for elem in first2Quests %}
{% include 'appviews/elements/questCard/questCard.html.twig' with {'elem': elem} %}
{% endfor %}

Resources