Redefining a block initially defined in an included view in the parent view with twig - symfony

I have a view A that includes a view B that defines a block Z. Can I have a view C that extends A and redefines block Z?
Need not be said that if i paste B into A (without using an include) it works.
For a practical example:
A is the base of a project.
B is the header of a project that includes a menu.
C is any page of the project.
I define a {% block active %}{% endblock %} for each item of the menu in B, that i want to redefine by {% block active %} class="active" {% endblock %} in C to apply certain styles to the current active menu item.
If this is not the way to go, which is the best workaround/solution?

Unfortunately, it's not possible or it wouldn't be as easy.
Why not bind a variable to the template from the controller and passing it to the nav through the include?
{% include MyAwesomeBundle:Modules:nav.html.twig with {activeItem: activeItem, activeItemClassName: activeItemClassName} %}
An alternative to what you want
{# in base layout template #}
{% block nav %}
{% include MyAwesomeBundle:Modules:nav.html.twig %}
{% endblock %}
{# in page template #}
{% extends base-layout.html.twig %}
{% block nav %}
{% include MyAwesomeBundle:Modules:nav_for_news.html.twig %} {# nav_for_news.html.twig extends nav.html.twig #}
{% endblock %}
This is the closest you can get from what you want
Check out the parent() twig function it's useful.

Related

Rendering a block in extended -> included template

Problem
In navbar.html.twig I have a block that looks like this:
//navbar.html.twig
{% block back_link %}{% endblock %}
This navbar is included by my base.html.twig.
//base.html.twig
{% include navbar.html.twig %}
And then my page template extends the base.
//page.html.twig
{% extends base.html.twig %}
...
{% block back_link %} Things i want in the navbar. {% endblock %}
But the things I want in the navbar don't show up in the navbar, because it's included by the base, so there's no parent/child relationship there.
Question
What's a good (or any) way to let me override a block in an included template in an extended template?
if you understand your idea right, you want to have some reusable content for a navbar, separated to navbar.html.twig that will possible to use in several templates?
So you can do it with "use" http://twig.sensiolabs.org/doc/tags/use.html
In navbar.html.twig
//navbar.html.twig
{% block back_link %}{% endblock %}
In base.html.twig.
//base.html.twig
{% use '::navbar.html.twig' %}
{{ block('back_link') }}
In page.html.twig
{% extends '::base.html.twig' %}
{% block back_link %} Things i want in the navbar. {% endblock %}

extends in symfony from multiple children

I have a base.html.twig with the basic html.
In the 'base' I have a {% block body %}{% endblock %} and a {% block javascript %}{% endblock %}
I call a 'form.html.twig' file from the Controller and the template extends the base.html.twig.
The 'form' contains the <form> and </form> tags and can contain a random numbers of sub templates/form elements:
'{% block body %}
{% for template in templates %}
{% embed template %}{% endembed %}
{% endfor %}
{% endblock %}'
The 'template' is perhaps a customer.html.twig, confirm.html.twig, vehicle.html.twig etc. etc. and they all have {% block body %} and {% block javascript %} - now for the question:
The content in the template files aren't moved to the blocks body/javascript. How do I get twig/symfony to move the content in the template files to the respective areas in the 'base.html.twig'?
Thank you for your time.
You want to use the use twig tag instead of the embed tag like this
{% use template %}
See more info here:
http://twig.sensiolabs.org/doc/tags/use.html

Twig simple overriding with include

I have a simple Twig template, were I wan to override a block from the include.
base.html.twig:
{% block razem %}
{% include '_ga.code.html.twig' %}
{% endblock %}
_ga.code.html.twig:
{% block wspolny %}
should be common
{% endblock %}
{% block googleAnalitics %}
for overridden
{% endblock %}
success.html.twig
{% extends 'base.hmtl.twig' %}
{% block razem %}
{{ parent('wspolny') }}
{% block googleAnalitics %}
overriding part
{% endblock %}
{% endblock %}
Where is the error? http://twigfiddle.com/jsuk6a
I expected to render something like this:
should be common
overriding part
In twig you can not override blocks in a include. For this you have to use embed, but have to do this in the using template, not in the base one.
base.html.twig:
{% block razem %}{% endblock %}
_ga.code.html.twig:
{% block wspolny %}
should be common
{% endblock %}
{% block googleAnalitics %}
for overridden
{% endblock %}
success.html.twig
{% extends 'base.hmtl.twig' %}
{% block razem %}
{% embed '_ga.code.html.twig' %}
{% block googleAnalitics %}
overriding part
{% endblock %}
{% endembed %}
{% endblock %}
I think that the best way to override a block and reuse some others is to extend the base template where you want to perform an overriding (maybe adding some code to the pre-existing one) and to apply the so called horizontal reuse:
Horizontal reuse is an advanced Twig feature that is hardly ever needed in regular templates. It is mainly used by projects that need to make template blocks reusable without using inheritance.
Starting from that point, you should simply use the base.html.twig template and extend _ga.code.html.twig as follows:
success.html.twig
{% extends '_ga.code.hmtl.twig' %}
{# Simply use base - without overriding #}
{% use 'base.hmtl.twig' %}
{% block googleAnalitics %}
overriding part
{% endblock %}
If you want to make an overload of a single block you could also use the parent() function; so, you can add some other information to an extended block.
If you need something more complex you should go for dynamic inheritance.
{% extends ['base.html.twig', '_ga.code.html.twig'] %}

How to check if a block exists in a twig template - Symfony2

Imagine I have something like this in my twig template
{% block posLeft %}
-----
{%endblock%}
Is there any way to check for existance of the posLeft block without calling to:
block("posLeft")
And check the return value of the posBlock to varify the existance. I am a newbie in Symfony2 + Twig.
You can solve it like this, if you want to display a certain block only if it has content. Hope, this is what you're looking for.
Example index.html.twig
{% set _block = block('dynamic') %}
{% if _block is not empty %}
{{ _block|raw }}
{% endif %}
Example part.html.twig
{% extends "index.html.twig" %}
{% block dynamic %}
Block content goes here.
{% endblock %}
You can do it like this:
{% if block('posLeft') %}
...
{% endif %}
But it is not efficient if you need output of rendered block.
So if you will need block output you should assign it to variable in the first place
and then do assertions
The other answers here do not work for twig 2.1 (I've not tested on ~2.0), so here's a small update:
{% if block('dynamic') is defined %}
{{ block('dynamic')|raw }}
{% endif %}
Note that the line to render the block is not:
{% block dynamic %}
{# this wont work #}
{% endblock %}
This wont work because the block will be rendered during compile, and so the test will return true that it exists (as its tested at runtime). So you need to render the block with {{ block('dynamic')|raw }} instead as this doesn't actually define the block in the template.
First check, which Twig version you are using inside your Symfony project, because the answers here are only for Twig 1.
If you are using Twig 2 you are lucky. According to the Twig documentation, you can use the defined test to check if the block exists in the current template context.
{% if block("dynamic") is defined %}
...
{% endif %}
I have written a little TwigExtension to check if the block gets called inside the if statement and it seems like Twig only really checks if the block exists and does not call it.
The link to the docs: https://twig.symfony.com/doc/2.x/functions/block.html
If you are using Twig 1, the old answer at https://stackoverflow.com/a/13806784/6458657 is still correct.
Twig 2.x
{{ (block("posLeft")) ?? '' }}
If you want to display a block if it's defined or not in one line. Might be a little kludgy but satisfies my needs without a bunch of if..then logic.
Just want to provide another example which worked for me.
<body
{% if block('ngapp') is not empty %}ng-app="{% block ngapp %}{% endblock %}"{% endif %}
>
This allows me in child templates declare {% block ngapp 'myApp' %} and have it displayed within parent.
This was needed because on some pages I was bootstrapping Angular manually via (angular.bootstrap('moduleName', rootElement)) and Angular does not like empty ng-app='' directive and breaks in weird ways.
The accepted answer didn't work for me in Twig 3.3.10, throwing an error that the block wasn't defined.
To solve this and define a block whose contents are conditionally wrapped in a container, only if any block content is set, this worked:
Parent template with block definition and wrapper element
{# parent.twig #}
<h1>Hello. I am the parent.</h1>
{% if block('sidebar') is not empty %}
<div class="sidebar-container">
{% block sidebar %}{% endblock %}
</div>
{% endif %}
Child template setting block content
{% extends 'parent.twig' %}
{% block sidebar %}
Sidebar content from child template
{% endblock %}
Output – block content inside wrapper:
<h1>Hello. I am the parent.</h1>
<div class="sidebar-container">
Sidebar content from child template
</div>
Child template not setting block content
{% extends 'parent.twig' %}
{# sidebar block not set in this one... #}
Output – no empty wrapper element:
<h1>Hello. I am the parent.</h1>

Symfony2 inherit from two form templates

I've set my forms to use a custom template (that produces a DL) and that works fine
twig:
form:
resources:
- 'myBundle:Form:row.html.twig'
But then I want to customise one row of one form and I think I have to do this
{% form_theme edit_form _self, ' %}
{% block _startYear_row %}
{% block form_row %}
{{ parent() }}
<div id="startCalendaryear"></div>
{% endblock %}
{% endblock %}
That make the entire form inherit from _self and loses the customisation of row.html.twig.
How can I set a custom template for all forms while still overriding a single row on one of them?

Resources