How to reuse block in an included template using twig - twig

I have a userDashboard.html.twig template like this:
{% extends "AcmeDemoBundle::base.html.twig" %}
{% block content %}
<h1>Name</h1>
{% endblock %}
{% include "AcmeDemoBundle::statistics.html.twig" %}
The controller call this template(userDashboard).
And a statistics.html.twig where I try to override or extend the content block:
{% extends "AcmeDemoBundle::userDashboard.html.twig" %}
{% block content %}
{{ parent() }}
Something
{% endblock %}
My problem is that I can't do this way. Can somebody recommend a solution?

There's embed which basically lets you include templates while overriding some of their blocks:
{% embed "AcmeDemoBundle::userDashboard.html.twig" %}
{% block content %}
{{ parent() }}
Something
{% endblock %}
{% endembed %}

Related

Twig {% extends %} does not pass variables

I use Kohana with twig and extend a template within a template. Param, which is available in my template is not passed to the extended template. How to pass all or at least that value to the extended template?
{% extends 'customer/main' %}
{% block content %}
Will show the content of my_param:{{ my_param }}
{% endblock content %}
File: customer/main.html
{% extends 'main' %}
{% block middle %}
Will NOT show the content of my_param:{{ my_param }}
{% block content %}{% endblock content %}
{% endblock middle %}

Use grandparent block

I have the following twig templates:
{# layout.twig #}
{% block content %}
THIS IS LAYOUT
{% endblock %}
{# secondary_layout.twig #}
{% extends layout.twig %}
{% block content %}
THIS IS SECONDARY_LAYOUT
{% endblock %}
{# mypage.twig #}
{% extends secondary_layout.twig %}
{% block content %}
{# I WOULD LIKE TO USE layout content block here #}
{% endblock %}
I can call parent() inside the content block in mypage.twig, but how to use a grandparent instead?
There are situations, in which you can achieve this. Unfortunately not in your case. However, it works if only "horizontal re-use" is used (use keyword), but not with inheritance (extends). This for instance applies to form themes.
In my case I defined a form theme which inherits from the bootstrap 3 form theme. The bootstrap theme itself inherits from "form_div_layout". I wanted to override the choice widget and include the grand parent's (form_div_layout) block content, because the bootstrap version of the block didn't fit for me in this single case. So, basically a very similar problem.
This can be solved by inheriting from both, the parent (bootstrap_3_layout) and grand parent layout (form_div_layout), while declaring an alias for the grand parent block to be overridden:
{# my_form_theme.html.twig #}
{% use 'form_div_layout.html.twig' with choice_widget_collapsed as base_choice_widget_collapsed %}
{% use 'bootstrap_3_layout.html.twig' %}
{% block choice_widget_collapsed -%}
{# There is no "grandparent()" function, so instead we can do this: #}
{{- block('base_choice_widget_collapsed') -}}
{%- endblock %}
I'm writing this answer, although it doesn't answer the actual question. But other people will probably also find this question when googling for such a "grandparent"-feature and maybe they'll give up unnecessarily, when they read that it's impossible here.
Ok by writing the problem I got one solution, just modify secondary_layout
{# secondary_layout.twig #}
{% extends layout.twig %}
{% block content %}
{% if use_layout_block %}
{{ parent() }}
{% else %}
THIS IS SECONDARY_LAYOUT
{% endif %}
{% endblock %}
{# mypage.twig #}
{% extends secondary_layout.twig %}
{% block content %}
{% set use_layout_block = true %}
{% endblock %}
It may help someone.
If someone got another solution, feel free to answer.
You can include the block of any template with the function block().
block - Documentation - Twig
block(<block_name>, [template_name])
In your case, the solution could be as follows:
{# mypage.twig #}
{% extends secondary_layout.twig %}
{% block content %}
{{ block('content', 'layout.twig') }}
{% endblock %}

Access block from included file

I want to access a block inside an included file.
Something like:
{#template A #}
some HTML
{% block blockA %}
{% endblock blockA %}
some HTML
{% block blockB %}
{% endblock blockB %}
some HTML
{#template B #}
{% extends A %}
{% block blockA %}
{% include C %}
some HTML
{% endblock %}
{#template C #}
{% block blockB %}
some HTML
{% endblock%}
All the HTML that i put on template C didnt go inside "blockB".
I think you are looking for embed instead of include.
Twig Documentation

Is it possible to turn on spaceless mode only in certain situations in twig?

I want to do something like this:
{% if compress %}{% spaceless %}{% endif %}
...
{% if compress %}{% endspaceless %}{% endif %}
I'm trying to pass ['compress' => true] to the template from PHP to turn on spaceless mode. But it causes an error; template tags need to be nested properly.
Is there any technique that would let me turn spaceless on/off from PHP?
You would have to restructure your template to do something like this instead.
{% import _self as example %}
{% macro stuff(obj) %}
output stuff with {{ obj.name }}, etc...
{% endmacro %}
{% if compress %}
{% spaceless %}
{{ example.stuff(bla) }}
{% endspaceless %}
{% else %}
{{ example.stuff(bla) }}
{% endif %}
Using macros avoids you have to duplicate the content. The import statement at the top is important, so don't forget it.
page.twig:
{% block page %}
page content
{% endblock %}
index.twig:
{% extends 'page.twig' %}
{% block page %}
{% if compress %}
{% spaceless %}
{{ parent() }}
{% endspaceless %}
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

Dynamic block name in TWIG

I need to add multiple blocks in my template, every with different name.
{% for item from items %}
{% block item.name %}sometext{% endblock %}
{% endfor %}
But I get error. How can I do this ?
In
Dynamic block names are not possible with Twig. There has been a discussion about it over at GitHub.
You can load blocks dynamically using the block function.
{% for item in items %}
{{ block( item.name )|raw }}
{% endfor %}
Twig documentation for the block function
If I understood the question correctly, you can do this (use parent context):
parent.html.twig
{% for item from items %}
{% set currentLoopItemName = item.name %}
{% block item_loop %}sometext{% endblock %}
{% endfor %}
override.html.twig
{% extends "base.html" %}
{% block item_loop %}
{% if item.name == 'custom' %}
// do something
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}
I was attempting to do the same thing and found a solution using the template_from_string function.
_items.html.twig
{% for item in items %}
{{ '{% block ' ~ item.name ~ ' %}'}}
sometext
{{ '{% endblock %}' }}
{% endfor %}
enter code here
page.html.twig
{% embed template_from_string(include('_items.html.twig')) %}
{% block someItemName %} someDifferentText {% endblock %}
{% endembed %}
What's happening is the block tags are initially being created as text. Then we use the include function to get the rendered content of _items, as a string. Finally, we convert that string to a working template (which we can embed or extend).
This works because the template_from_string function will create and compile a template at runtime, where as normally twig is compiled before hand and unchanged at runtime.

Resources