Pass Block through multiple Templates - twig

I am trying to set up some common templates, that I want to use throughout my site.
Starting with a template in order to render Users. I have devided this into two different subtemplates:
users.html.twig (Template in order to show a table of Users)
user.html.twig (Template to render a single User)
Depending on the Controller this subtemplates are "included" I may want to add some buttons for each user.
Lets assume I have an action where I can search for users. This Action has the template search.html.twig
Now I want to include within my search.html.twig the users.html.twig which itself includes user.html.twig. The tricky part is, I want to define in search.html.twig a single block that is rendered in user.html.twig. I tried it with embed, but unfortunately it renders nothing:
search.html.twig
{% embed 'StregoUserBundle:Entity:users.html.twig' with {'users': results, 'perRow' : 3} %}
{% block user_additional %}
TOOOOOOOOOOOOP
{% endblock user_additional %}
{% endembed %}
users.html.twig
{% block user_table %}
{% for user in users %}
<div >
{% embed 'StregoUserBundle:Entity:user.html.twig' with {'user': user} %}
{% block user_additional %}
{{ parent()}}
{% endblock user_additional %}
{% endembed %}
</div>
{% endfor %}
{% endblock user_table %}
user.html.twig
{% block single_user %}
<div class="people-list">
<a href="{{ path('profile_show', { 'username': user.username }) }}">
<img src="{{ user.profilePic | imagine_filter('profile_thumb') }}" alt="{{ user.username }}" class="img-polaroid">
</a>
<h3>{{ user.username }}</h3>
<h3><small>{{ user.firstName }} {{ user.lastName }}</small></h3>
{% block user_additional %}
{% endblock user_additional %}
</div>
{% endblock single_user %}
I have tried several combinations of {{ block('XXX')}}, includes, embed, use etc... but did not find a solution.

Should't
{% endembed %}
be
{% embeded %}

Related

Using Twig to declare template and pass in additional content between the parent template's block

I have the following code that I repeat multiple times in my layout:
<div id="hi">
<div class="howAreYou">
<p class="fineTYForAsking">
<!-- additional HTML logic goes here -->
</p>
</div>
</div>
How can I put in the above html into a single Twig template, and then use that template and put in my additional specific html in the <!-- additional HTML logic goes here --> section?
You could just define blocks and embed the template where ever you want
partial.twig.html
<div id="{{ id | default('hi') }}">
<div class="howAreYou">
<p class="fineTYForAsking">
{% block content %}
{% endblock %}
</p>
</div>
</div>
template.twig.html
{% embed "partial.html.twig" with { 'id' : 'foo' } %}
{% block content %}
Lorem Ipsum
{% endblock %}
{% endembed %}
You could also use an embed in a for-loop. Variables known inside the loop, are also know in the embedded file, e.g.
item.html.twig
<div{% if item.id|default %} id="{{ item.id }}"{% endif %}>
<div class="howAreYou">
<p class="fineTYForAsking">
{% block title %}
{% if item.title is defined %}
<h1>{{ item.title }}</h1>
{% endif %}
{% endblock %}
{% block content %}
{% if item.content is defined %}
<p>{{ item.content }}</p>
{% endif %}
{% endblock %}
</p>
</div>
</div>
template.html.twig
{% for item in items %}
{% embed "item.twig" %}
{% endembed %}
{% endfor %}
demo

How to reduce duplication in Twig template

I have an if/else condition in a twig template which switches the out tag of a block of code, however the inner block is the same. Is there a way to reduce the duplication without creating a separate file?
This is what I have at the moment:
{% if condition %}
<a href="">
{{ content }}
</a>
{% else %}
<span>
{{ content }}
</span>
{% endif %}
I was hoping to do something such as:
{% if condition %}
<a href="">
{% include mycontent %}
</a>
{% else %}
<span>
{% include mycontent %}
</span>
{% endif %}
{% mycontent %}
{{ content }}
{% endmycontent %}
Is such a thing possible?
If you don't want to use extra files you could use macro's :
{% import _self as macro %}
{% macro foo(content) %}
{{ content }}
{% endmacro %}
{% for condition in [0, 1, 0, 1, ] %}
{% if condition %}
{{ macro.foo('Bar') }}
{% else %}
<span>{{ macro.foo('Bar') }}</span>
{% endif %}
{% endfor %}
fiddle
What you want to do has to be done using the normal syntax. an extra file. and include this file.
But if u want to do this without extra file. use the {% set variablecontent = "put content here" %} and then in your "{% mycontent %}" part u put {{ variablecontent }}
hope this helps

Wrap content by an element that satisfies a condition in Twig

I often have similar boilerplate code in Twig:
{% if (somelongcond) %}
<div>
{% endif %}
<p>Some long content</p>
{% if (somelongcond) %}
</div>
{% endif %}
The problem with the above is if the condition is changed, it can be a maintenance nightmare, I also have to go look all the way down to find the matching if statement and see if the condition is the same.
An alternative is something like this:
{% if (somelongcond) %}
<div>
{% include 'content' %}
</div>
{% endif %}
{% include 'content' %}
But that requires creating a new file, which can become a mess if I need to do this many times.
Is there a better way to do the above.
There is a good example here: https://gist.github.com/jakedohm/39190ec533e69e83b9cee4bdf3898a60
Result:
{% set content %}
<p>Some long content</p>
{% endset %}
{% if somelongcond %}
<div>
{{ content }}
</div>
{% else %}
{{ content }}
{% endif %}
This is a bit shorter
{{ if somelongcond ? '<div>'|raw }}
<p>Some long content</p>
{{ if somelongcond ? '</div>'|raw }}
Then, if the same condition is repeated, you can maybe set it at the top of your file, then if you need to change it you only have to do it once.
{% if somelongcond %}
{% set cond = true %}
{% else %}
{% set cond = false %}
{% endif %}
{{ if cond ? '<div>'|raw }}
<p>Some long content</p>
{{ if cond ? '</div>'|raw }}

Twig embed block not working when its within a loop?

I need to place a twig template into my page and place another twig template inside it.
In page.twig:
{% embed "parent.twig" %}
{% block something %}
{% include "child.twig" %}
{% endblock %}
{% endembed %}
In parent.twig:
{% set array = ['', '', '']
%}
<div class="parent">
{% for i in array %}
<div class="parent__item">
{% block cardBoard %}
{% endblock %}
</div>
{% endfor %}
</div>
The problem is that the block doesn't work when its within a loop. I can edit page.twig all I like but I would rather not change parent.twig if possible as its consumed by other applications.
Why do you put a block inside a for loop ? You can't have 2 blocks defined with the same name.
In your case it will try to put this in your template 3 times :
<div class="parent__item">
{% block cardBoard %}
{% endblock %}
</div>
This will create a 500 server error :
The block 'cardBoard' has already been defined line '' in :parent.twig at line ''.
If you really want to have content depending on the values in your array, put the block opening and closing outside the for loop.
Like this for example :
{% set array = ['', '', '']%}
<div class="parent__item">
{% block cardBoards %}
{% for i in array %}
<div class="cardBoard{{ i }}>
</div>
{% endfor %}
{% endblock %}
</div>

Navigation link works on mobile but not on desktop

i have this website http://sds-test.nowcommu.myhostpoint.ch/de (please use the "de" at the end) and the last link of the navigation "RECHENZENTRUM" does not works on desktop but works on mobile. How can i solve it? This is the twig code:
{% extends 'partials/base.html.twig' %}
{% set show_onpage_menu = header.onpage_menu == true or header.onpage_menu is null %}
{% macro pageLinkName(text) %}{{ text|lower|replace({' ':'_'}) }}{% endmacro %}
{% block javascripts %}
{% if show_onpage_menu %}
{% do assets.add('theme://js/singlePageNav.min.js') %}
{% endif %}
{{ parent() }}
{% endblock %}
{% block bottom %}
{{ parent() }}
{% if show_onpage_menu %}
<script>
// singlePageNav initialization & configuration
$('#navbar').singlePageNav({
offset: $('#header').outerHeight(),
filter: ':not(.external)',
updateHash: true,
currentClass: 'active'
});
</script>
{% endif %}
{% endblock %}
{% block header_navigation %}
{% if show_onpage_menu %}
<ul class="navigation">
{% for module in page.collection() %}
{% set current_module = (module.active or module.activeChild) ? 'active' : '' %}
<li class="{{ current_module }}">{{ module.menu }}</li>
{% endfor %}
{% set datacenter_page = page.find('/services/datacenter') %}
<li>{{ datacenter_page.menu() }}</li>
</ul>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}
{% block content %}
{{ page.content }}
{% for module in page.collection() %}
<div id="{{ _self.pageLinkName(module.menu) }}"></div>
{{ module.content }}
{% endfor %}
{% endblock %}
The 'rechenzentrum' link is rendered correctly, and copying the link location via right click gives a correct URL that opens a seemingly correct page. So the template rendering is fine.
The link has two onclick handlers attached to it, though. Probably one of them fails and thus prevents navigation. (The JS is minified so I did not try to debug it.)

Resources