Pass variable in twig to included template
Asked Answered
H

5

6

I have set the rendering of an navigation menu en an separate twig template. Reason is the the menu is generated on two different places in the application.

Now I want to give a parameter to the navigation menu so I know from with place it is generated are these some small differences.

I tried the following code but the variable is not know in the navigation menu template:

{% set menuType = 'user' %}
{% include 'MyBundle:nav.html.twig' with menuType %}

Also tried:

{% include 'MyBundle:nav.html.twig' with {'menuType': 'user'} %}

In both case twig generated the error that {{ menuType }} does not exists?

Hexahydrate answered 12/1, 2017 at 22:53 Comment(0)
F
7

Surprisingly, while I thought it would be possible to do like you to pass a simple variable, it appears only arrays are accepted as passed values. (While the two examples of the include doc are arrays, this isn't specifically precised.)

In your case, you have to write it this way:

{% set menuType = 'user' %}
{% include 'MyBundle:nav.html.twig' with {menuType:menuType} only %}

Note: I've added the only keyword to disable the access to the context. Without it you don't need to pass the variable to the included templates as they will have access to them. (It's a good practice to disable it.)

Here is a Twigfiddle with some tests and dumps: https://twigfiddle.com/gtnqvv

{% set menuType = 'user' %}
{% set vars = {'foo': 'bar'} %}
{% set z = 'bob' %}

{# vars dumps ommitted here, see the fiddle. #}

{#% include '1.html.twig' with menuType only %#}
{% include '1.html.twig' with {menuType:menuType} only %}
{% include '2.html.twig' with vars only %}
{% include '3.html.twig' with {z:z} only %}
{#% include '3.html.twig' with z only %#}

The first and last commented lines doesn't work, as you know, here is the error:

Uncaught TypeError: Argument 1 passed to Twig_Template::display() must be of the type array, string given

The second works as you want, you just have to make it an array. (Strange anyway)

The third line is a test from the Twig doc, and the fourth is a test with another variable name, just to be sure.

Forerunner answered 12/1, 2017 at 23:34 Comment(1)
My plus for the 'only' keyword.Retaliate
Q
2

As long as a variable is available, or included with the parent template, it is available to any included or child template.

Ex: Controller:

return $this->render('CmsBundle:EmailBulk:edit.html.twig', array(
            'entity' => $entity,
            'form'   => $editForm->createView(),
            'tokens' => $tokens
        ));

Then, edit.html.twig:

{% block body -%}
    <div class="panel panel-default animated fadeIn delay-400">
        <div class="panel-heading">
            blah blah blah
        </div>
        <div class="panel-body">
            {{ include('CmsBundle:EmailBulk:form.html.twig') }}
        </div>
    </div>
{% endblock %}

The 'form' variable from the controller is available to the included template form.html.twig

Quinine answered 13/1, 2017 at 1:17 Comment(1)
This works from the controller. But when I define a new variable {% set menuType = 'user' %} in the parent twig, it is not passed to the child twig.Hexahydrate
D
1

I created a sample twigfiddle for you here:

https://twigfiddle.com/fpzv26

You need something like this:

{% set vars = { 'menuType' : 'user'} %}
{% include 'MyBundle:nav.html.twig' with vars %}
Desorb answered 12/1, 2017 at 23:24 Comment(3)
In the twigfiddle I had to shorten the length of the name of the template file. I complained about a limit of 21 characters, so I used "nav.html.twig".Desorb
It doesn't allow to pass a variable which is not an array like @Tom's menuType though.Forerunner
Right @Forerunner , I saw your post. Actually when I made my twigfiddle I noticed that too. I thought the OP's original post should work too, that's why I went to twigfiddle. I found the same thing that you did. It needs to be an array. Hopefully the OP understands this.Desorb
G
0

I use this in my code and it works for me. The var foo is used in baz.html.twig directly:

{% set foo = 'foo' %}
{{ include ('MyBundle:bar:baz.html.twig') }}

In twig docs it says:

Included templates have access to the variables of the active context. [...] The context is passed by default to the template but you can also pass additional variables

Geyserite answered 12/1, 2017 at 23:15 Comment(2)
Note it's a good practice do disable the access to the context with the only keyword.Forerunner
@DarkBee In general, it's good practice to limit the access code has to its surrounding scope, for the same reason as why global variables are (mostly) bad practice. Twig passes the whole parent context to a child include by default, which is unnecessary if the child template only requires one particular variable.Alga
B
-1

Twig 3 recommends using the include function instead of the include tag which will look like this:

{{ include('MyBundle:nav.html.twig', {menuType: user}, with_context = false) }}

with_context = false blocks passing of any other variables than the ones inside the include.

Buckthorn answered 11/6, 2023 at 7:20 Comment(7)
This is not any different than twig 2Spur
In Twig 3, parameters are passed like in a function include(template, {}, ...) while the answer from @Forerunner shows a different style include template with .... I don't know when it changed but it's definitely differentBuckthorn
Nothing has changed, you have the function {{ include ... }} and the tag {% include .... %}Spur
The official guide mentions only the function include not the tag twig.symfony.com/doc/3.x/…Buckthorn
No it doesn't. Watch the demo I've posted, it's running in twig 2.XSpur
As per your link: It is recommended to use the include function instead as it provides the same features with a bit more flexibilityBuckthorn
That's not even what is asked by OPSpur

© 2022 - 2024 — McMap. All rights reserved.