I'm following a tutorial about symfony2 framework ..
I've already managed to render a template which inherits from the base layout as follows
# ::layout.html.twig > MyvendorBlogBundle:blog:index.html.twig
# then inside the controller action, call
$this->render('MyvendorBlogBundle:Blog:index.html.twig', ['foo'=>'bar']);
I decided to add an intermediate template in between but I'm having trouble to make twig templating engine to render my 3 layouts cascaded templates: As mentioned above, i'm not able to get any output using the following schem but a blank page instead (no raised exceptions and the source only contains the base.html.twig code)
# ::layout.html.twig > MyvendorBlogBundle::layout.html.twig > MyvendorBlogBundle:blog:index.html.twig
Here are my templates
base (app/Ressources/views):
<html>
<head>
<meta charset="UTF-8" />
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
</head>
<body>
<div id="app-container">
<header id="app-header">
</header>
<div id="app-page-content">
{% block body %}{% endblock %}
</div>
</div>
{% block javascripts %}{% endblock %}
{# FLASH BAG HANDLING #}
{% for label, flashes in app.session.flashbag.all %}
{% for flash in flashes %}
<div class="alert alert-{{ label }}">
{{ flash }}
</div>
{% endfor %}
{% endfor %}
</body>
</html>
Then the blog bundle layout (src/Myvendor/BlogBundle/Resources/views):
{% extends "::base.html.twig" %}
{% block body %}
{% block side %}
<div id="blog-side">
<nav>
1rst link
</nav>
</div>
{% endblock %}
{% block main %}{% endblock %}
{% endblock %}
Now the index page template (src/Myvendor/BlogBundle/Resources/views/Blog):
{% extends "MyvendorBlogBundle::layout.html.twig" %}
{% block main %}
<h1>{{ caption }} !</h1>
{% if caption is not empty %}
{{ caption }}
{% endif %}
{% endblock %}
And finally the controller
namespace Myvendor\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class BlogController extends Controller
{
public function indexAction()
{
return $this->render('MyvendorBlogBundle:Blog:index.html.twig', ['caption'=>'hello!']);
}
}
May someone spot what's going on here ?
The pb maybe obvious but I've been stuck for a couple of hours now and blocks nesting seems perfect to me :/
Related
Is there a way to specify an "extend" in Twig to exclude one of its included partials ?
To better explain myself, here is my base.html.twig
<body>
{% include '/main/_navbar.html.twig' %}
{% block body %}
{% for flashError in app.flashes('success') %}
<div class="alert alert-success" role="alert">{{ message }}</div>
{% endfor %}
{% endblock %}
{% include '/main/_footer.html.twig' %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="{{ asset('script/app.js') }}"></script>
</body>
On my login page, I do not need my _navbar.html.twig partial. Is there a way to not include (exclude) it knowing my view extends from this base template ? Are there any "options" I could pass behind that extends ?
This is the code I use to extend my base template on my login page :
{% extends 'base.html.twig' %}
Just wrap the include you don't want to include in a seperate block, then override the block with empty content, e.g.
base.html.twig
<body>
{% block nav %}
{% include '/main/_navbar.html.twig' %}
{% endblock %}
{% block body %}
{% for flashError in app.flashes('success') %}
<div class="alert alert-success" role="alert">{{ message }}</div>
{% endfor %}
{% endblock %}
{% include '/main/_footer.html.twig' %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="{{ asset('script/app.js') }}"></script>
</body>
login.html.twig
{% extends "base.html.twig" %}
{% block nav %}{% endblock %}
demo
I am awfully new to Symfony 4 and Twig 2.
All I want to do is get the basic functionality of extending templates to work.
Unfortunately the documentation of Symfony and Twig do not explain what I am looking for (Twig documentation is mostly just a collection of code with only minimal explanations). Or I don't understand... :)
This is simple.
I got the usual base.html.twig:
base.html.twig
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
{% block body %}Old Content{% endblock %}
{% block javascripts %}{% endblock %}
</body>
</html>
I only added some default text into the body block.
Next a simple file that should extend the one above:
body.html.twig
{% extends "base.html.twig" %}
{% block body %}
New content
{% endblock %}
To output all this I created a controller:
baseController.php
<?php
namespace App\Controller;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class baseController extends AbstractController
{
/**
* #Route("/")
*/
public function base()
{
return $this->render('base.html.twig');
}
}
?>
Tested the templates in twigfiddle.com and all worked well, so they are surely fine.
The above setup outputs the base.html.twig just fine (see the "Old Content" text, but completely ignore the body.html.twig. So the obvious question: what am I overlooking/which basic concept am I not grasping?
Thank you for your kind help.
base.html.twig is your skeleton and body.html.twig is your page specific implementation. Your controller should always render the body.html.twig, which will override blocks found inside the extended base.html.twig.
Some examples from the top of my head:
base.html.twig:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
{% include 'header.html.twig' %}
{% block body %}{% endblock %}
{% include 'footer.html.twig' %}
</body>
{% block javascripts %}{% endblock %}
</html>
home.html.twig:
{% extends "base.html.twig" %}
{% block body %}
<h1>header of this page</h1>
{% include 'newsletter-subscribe.html.twig' %}
{% include 'greeting.html.twig' with { name: 'Max' } %}
<p>Some content</p>
{% endblock %}
greeting.html.twig:
Hello {{ name }}
just creat the header and footer yourself. ensure you render home.html.twig in your controller.
If you want to dive into it and must use nested blocks, make use of https://twig.symfony.com/doc/2.x/functions/parent.html
base.html.twig:
{% block body %}
Hello World
{% endblock %}
home.html.twig:
{% extends 'base.html.twig' %}
{% block body %}
{{ parent() }}
how are you
{% endblock %}
should output Hello world how are you. I would discourage that function though, because the dependency is not clear from a designers perspective. Also be careful with embed, it has a higher impact on twig then include or simple blocks.
Need to use a variable that is in the parent template.
I have layout:
<html>
<head>
</head>
<body>
{%block content %}
{% set com = 0 %}
DEFALUT CONTENT
{% endblock %}
</body>
</html>
And children template:
{% extends '::layout.html.twig' %}
{% block content %}
HOW USE LAYOUT VARIABLE HERE? LIKE: {{ com }}
{% endblock %}
Thanks in advance!
Use the parent() twig function.
{% extends '::layout.html.twig' %}
{% block content %}
{{ parent() }}
{{ com }}
{% endblock %}
The above code will render a template like :
<html>
<head>
</head>
<body>
{% block content %}
{% set com = 0 %}
DEFAULT CONTENT
{{ com }}
{% endblock %}
</body>
</html>
I would like to use a kind of global array to define what javascripts should be loaded at the end of the page. This way, I can dynamically add javascript files.
The problem is that the base template is being rendered first. Imagine this base html:
{% set javascriptList = [ 'js/vendor/jquery-1.10.1.min.js', 'js/vendor/bootstrap.min.js', 'js/main.js' ] %}
<!DOCTYPE html>
<head>
<title>my project</title>
</head>
<body>
{% block container %}
content goes here
{% endblock %}
{% block javascripts %}
{% for js in javascriptList %}
<script src="{{ asset(js) }}"></script>
{% endfor %}
{% endblock %}
</body>
</html>
Then I would have a page, something like this:
{% extends base.html.twig %}
{% block container %}
<h1>Demo</h1>
Bla bla
Code I want to reuse:
{% include 'code-with-js.html.twig' %}
{% endblock %}
Then my code-with-js.html.twig would be:
<div id="DemoContent">
Some content, with a tooltip thingy maybe.
</div>
{% set javascriptList = javascriptList|merge(['js/tooltip.js']) %}
So, using this setup, I can make sure that the correct javascript is being added, when the piece of html is being included.
But, this doesn't work of course. The base html is rendered first, so the element will be added to the javascriptList array after it has been rendered. My approach must be wrong.
In my project this reusable code is actually a form with some extra buttons that insert content to the textarea's (so a tinyMCE, but much much much more simplistic). I would like to reuse this code on several pages (create, update).
Any thoughts are welcome!
First of all I recommend you to add a javascript block in your base.html.twig :
You can add a block in your base.html.twig after your script load :
{% block javascripts %}
{% for js in javascriptList %}
<script src="{{ asset(js) }}"></script>
{% endfor %}
{% endblock %}
<script type="text/javascript">
{% block afterJavascriptLoad %}
{% endblock %}
</script>
With inheritance you'll be able to execute javascript after all script load in nested template :
{% extends base.html.twig %}
{% block afterJavascriptLoad %}
//Your code to be executed after base.html script load
{% endblock %}
Having html code and javascript code is not a very good practice. For exemple if you have 3 tinyMCE redactor in your page, you'll load 3 times tinyMCE.
For me the best way is to have your template like this :
base.html.twig:
{% block container %}
content goes here
{% endblock %}
{% block javascripts %}
{% for js in javascriptList %}
<script src="{{ asset(js) }}"></script>
{% endfor %}
{% endblock %}
{% block afterJavascriptLoad %}
//Your code to be executed after base.html script load
{% endblock %}
pageWithTinyMCE.html.twig :
{% extends base.html.twig %}
{% block container %}
<h1>Demo</h1>
Bla bla
Code I want to reuse:
{% include 'code-without-js.html.twig' %}
{% set javascriptList = javascriptList|merge(['js/tooltip.js']) %}
{% endblock %}
{% block afterJavascriptLoad %}
//Custom javascript for the page
{% endblock %}
I use symfony 2.0.9.
Code of base.html.twig:
<html>
<head>
<title>title</title>
{% block stylesheets %}
<link href="{{ asset('css/main.css') }}" type="text/css" rel="stylesheet" />
{% endblock %}
{% block javascript %}
{% endblock %}
</head>
<body>
<div class="sidebar">{% block sidebar %}{% endblock %}</div>
<div class="content">{% block content %}{% endblock %}</div>
</body>
My Bundle have own layout.html.twig, which being extended by Controllers, for example PostController.php with action showAction.
Code of layout.html.twig
{% extends '::base.html.twig' %}
{% block stylesheets %}
{{ parent() }}
...something
{% endblock %}
{% block navigation %}
...list of menus
{% endblock %}
{% block sidebar %}
{% render "DevMyBundle:Page:sidebar" %}
{% endblock %}
How can access to block 'javascript' in base.html.twig from sidebar.html.twig, which rendered by PageController like this in layout.html.twig: {% render "DevMyBundle:Page:sidebar" %} or How can i reorganize structure of my templating.
What for?: There are more blocks in sidebar may be. Each block call its own js. How? Thanks for advance.
Update: please, guys, help. There should be a simple answer. I have read twig docs, but im newbe in it. If i post this question not correctly, ask me.
One way would be to move the sidebar javascrpt to it's own template.
Something like this in layout.html.twig
{% block sidebar %}
{% render "ZaysoArbiterBundle:Test1\\Main:sidebar" %}
{% endblock %}
{% block javascript %}
{{ parent() }}
<script>Some layout javascript</script>
{% render "ZaysoArbiterBundle:Test1\\Main:sidebarjs" %}
{% endblock javascript %}