Can't override extended twig template block to empty - symfony

I'm using MopaBootstrapBundle in Symfony 2.1.3 with Twig templates.
This bundle has base.html.twig template which contains scripts block:
{% block foot_script %}
{# To only use a subset or add more js overwrite and copy paste this block
To speed up page loads save a copy of jQuery in your project and override this block to include the correct path
Otherwise the regeneration is done on every load in dev more with use_controller: true
#}
{% javascripts
'http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-transition.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-modal.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-dropdown.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-scrollspy.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-tab.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-tooltip.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-popover.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-alert.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-button.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-collapse.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-carousel.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-typeahead.js'
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-collection.js'
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-subnav.js'
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock foot_script %}
I'm extending it in my template using:
{% extends 'MopaBootstrapBundle::base.html.twig' %}
{% block foot_script %}{% endblock foot_script %}
But it still tries to load Bundle's base.html.twig template and I get:
An exception has been thrown during the compilation of a template
("Unable to find file
"#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-transition.js".")
in "MopaBootstrapBundle::base.html.twig".
What I've found out is, that if you extend it like this:
{% extends 'MopaBootstrapBundle::base.html.twig' %}
{% block foot_script %}
{% javascripts
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-typeahead.js'
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-collection.js'
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-subnav.js'
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock foot_script %}
Note the typeahead.js
I get:
An exception has been thrown during the compilation of a template
("Unable to find file
"#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-typeahead.js".")
in "MopaBootstrapBundle::base.html.twig".
If I remove just one line:
{% extends 'MopaBootstrapBundle::base.html.twig' %}
{% block foot_script %}
{% javascripts
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-collection.js'
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-subnav.js'
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock foot_script %}
I get:
An exception has been thrown during the compilation of a template
("Unable to find file
"#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-transition.js".")
in "MopaBootstrapBundle::base.html.twig".
It still tries to load all the scripst from base template.
Any suggestions how to override *foot_script* block to make it empty and not to load these JS files?

What you want is to embed the MopaBootstrapBundle::base.html.twig instead of extending it. You should use Twig's embed tag:
{% embed 'MopaBootstrapBundle::base.html.twig' %}
{% block foot_script %}{% endblock foot_script %}
{% endembed %}
From Twig's documentation:
The embed tag combines the behaviour of include and extends. It allows you to include another template's contents, just like include does. But it also allows you to override any block defined inside the included template, like when extending a template.

Related

Symfony2 - How to reference files from the web directory with {% javascripts %} in twig?

I'm using libraries like amcharts that have many js files.
I put amcharts in web/js/amcharts as suggested julesbou and then
{% block javascripts %}
{{ parent() }}
{% javascripts '/js/amcharts/amcharts.js' %}
<script src="{{ asset_url }}" type="text/javascript"> </script>
{% endjavascripts %}
{% endblock %}
But I get [exception] 500 | Internal Server Error | RuntimeException
[message] The source file "/amcharts/amcharts.js" does not exist.
Edit
To include a file under web try removing the forward slash from your path i.e.
{% javascripts 'js/amcharts/amcharts.js' %}
^ remove / here
Suppose you have put your javascripts sources named xyz.js in 'js/' folder is source then you will have to fetch this javascripts via your "app/resources/base.html" file loke this :
{% block javascripts %}
<script src="{{ asset('js/xyz.js') }}" type="text/javascript"> </script>
{% endblock %}
and when in remaining twig file you extends base.html.twig like below :
{% extends '::base.html.twig' %}
{% block display %}
{% endblockdisplay %}
it automatically fetch your javascripts . Even if you want to modify the javascripts code for that particular child twig then you will have to write like as :
{% extends '::base.html.twig' %}
{% block display %}
// Your display content here
{% endblockdisplay %}
{% block javascripts %}
{{ parent() }}
// Your changing code here
{% endblockjavascripts %}

Use array variable to load javascripts at bottom of the page

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 %}

load css in child of a twig

I have a super class twig which has the following block:
{% stylesheets filter='css_url_rewrite,?yui_css'
'#MainBundle/Resources/public/css/bootstrap.css'
'#MainBundle/Resources/public/css/vendor/*.css'
'#MainBundle/Resources/public/css/_normalize.css'
'#MainBundle/Resources/public/css/main.css'
'#MainBundle/Resources/public/css/fonts.css'
'#MainBundle/Resources/public/css/include/*.css'
'#MainBundle/Resources/public/css/footer.css'
%}
I have another twig that extends from the twig above, but I wanted to add an additional css on this page, so I did:
{% block stylesheets %}
{{ parent() }}
{% stylesheets filter='css_url_rewrite,?yui_css'
'#ShopiousMainBundle/Resources/public/css/shippingconfirm/*.css'
%}
{% endstylesheets %}
{% endblock %}
however this doesn't import the css that I have inside shippingconfirm,
Any idea on how to fix this?
You need to set the link element again in your stylesheets block. So it should work with the following:
{% block stylesheets %}
{{ parent() }}
{% stylesheets filter='css_url_rewrite,?yui_css'
'#ShopiousMainBundle/Resources/public/css/shippingconfirm/*.css' %}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}
{% endblock %}
But your additional stylesheets in the shippingconfirm folder will be in an extra file. Assetic won't put all stylesheets (css from parent and css from the current template) into one file.
A similar question was posted here: Combining Assetic Resources across inherited templates
There you can find some approaches to fix your problem.

Adding JS and CSS cleanly from included Twig templates

I'm looking to find out if there's a clean way to add JS and CSS from included templates.
So, for example, if layout.html.twig has:
{% include 'GenericBundle:Generic:page.html.twig' with {'data': data} %}
...
{% block javascript %}
{% javascripts
'#GenericBundle/Resources/public/js/app/jquery/jquery.min.js'
'#GenericBundle/Resources/public/js/lib/bootstrap/bootstrap.min.js'
%}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock %}
And in the generic bundle page I'd like to include some more Javascript but add it to the established Javascript block to keep to HTML and JS best practices.
Is there a clean way to do this? I'm using Symfony2, and could probably cludge together a solution using Singletons and such, but I'd rather a cleaner method if there's one available.
I know I'm a little late to the party, but with Twig 1.2, you can utilize the use tag and the block function:
GenericBundle:Generic:page.html.twig
{% block javascripts %}
<script src="..."></script>
{% endblock %}
{% block included_content %}
Bar
{% endblock %}
layout.html.twig
{% use 'GenericBundle:Generic:page.html.twig' with javascripts as page_javascripts %}
{% block javascript %}
{% javascripts
'#GenericBundle/Resources/public/js/app/jquery/jquery.min.js'
'#GenericBundle/Resources/public/js/lib/bootstrap/bootstrap.min.js'
%}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
{{ block('page_javascript') }} // Don't forget the 'braces'
{% endblock %}
...
{{ block('included_content') }} // Don't forget the 'braces'

Symfony2 Assetic + Twig Template JavaScript Inheritance

My problem:
I have 3 templates:
main.html.twig (main layout file)
layout.html.twig (a bundle specific layout override which contains some bundle specific JS tags)
create.html.twig (a page specific template file which also contains some page specific JS tags)
I am defining a block called 'javascript' in my base layout (main.html.twig), then overriding it (but calling {{ parent() }} in layout.html.twig. This works fine, and the JS tags from the main template file are still included above those in the layout.html.twig template.
I then do the same in the create.html.twig file, overriding the block as follows:
{% block javascripts %}
{{ parent() }}
{% javascripts '#BundleName/Resources/public/js/application.album.uploader.js'
'#BundleName/Resources/public/js/jquery.uploadify.js'
'#BundleName/Resources/public/js/swfuploadify.js' filter='?yui_js' %}
<script src='{{ asset_url }}' type='text/javascript'></script>
{% endjavascripts %}
{% endblock %}
At this point, instead of just overriding the javascript block in the parent (layout.html.twig) and including all the scripts defined in the templates above it, it does the following:
Dumps the <script> tags in the middle of the output (which causes an error, because in my main.html.twig file I am only including the jQuery library at the end of the HTML markup
Then it also dumps the scripts out along with the rest of the others (as I would expect it to)
I am not sure what is causing the scripts to be dumped in the middle of the create.html.twig template, and I'm also confused as to why they're being dumped to the screen twice (once in the middle of the create and then once at the bottom along with all the rest of my scripts from main.html.twig and layout.html.twig.
Has anyone got any ideas? Let me know if anything is unclear or if I can provide some more information.
EDIT:
File contents are below...
main.html.twig: https://gist.github.com/7f29353eaca0947528ce
layout.html.twig: https://gist.github.com/734947e9118b7765715e
create.html.twig: https://gist.github.com/c60c8d5c61e00ff86912
EDIT 2:
I've been having another look at the issue this morning and it looks as though its doing the same thing for stylesheets. I tried to define a new block called pagescripts in my layout.html.twig and then use the block in my create.html.twig but this had the same outcome, it just seems to dump the scripts and stylesheets wherever I use the
{% block pagescripts %}
(scripts here)
{% endblock}
I found the issue. In create.html.twig I was defining my {% block javascripts %} content inside inside my {% block content %}, so I assume Twig was rendering the output of the javascripts block inside the content block.
Moving the {% block javascripts %} content outside of the {% block content %} block fixed the issue.
Here is an example of main.html.twig:
<body>
{% block stylesheets %}
{% endblock %}
{% block jsscript %}
{% endblock %}
{% block content %}
{% endblock %}
</body>
into your create.html.twig
{% extends '::base.html.twig' %}
{% block jsscript %}
my javascript files...
{% endblock %}
{% block content %}
<h1>Create</h1>
<form action="{{ path('entity_create') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<p>
<button type="submit">Create</button>
</p>
</form>
{% endblock %}
If you still have issue, you can add a document ready function :
$(document).ready(function() {
// put all your jQuery goodness in here.
});

Resources