imagine you have a twig template (tplA.twig) that include an other one
<p>Twig template A</p>
{% set test = "in tpl A" %}
<p>first, variable is: {{ test }}</p>
{% include "tplB.twig" %}
<p>and the variable is: {{ test }}</p>
and the included template (tplB.twig)
<div>Content of tpl B</div>
{% set test = "now is tpl B" %}
What is the best way to set/change a variable in an included template and use it in the master template? How to use globals? Note that I can't use blocks and extends, and I'm not using Symfony.
Many thanks
EDIT
The real context is a very basic multilingual structure. For a page, I have one master template:
<h1>{{ i18n('mainTitle') }}</h1>
<h2>current language (fr, en): {{ ln }}</h2>
<!-- here a list of photos, but not in a foreach loop -->
<div>
<div>
<img src="/same/for/all/languages-a.jpg" alt="localized A" />
<span>localized A</span>
</div>
<div>
<img src="/same/for/all/languages-b.jpg" alt="localized B" />
<span>localized B</span>
</div>
<!-- etc. -->
</div>
It is a very small website, so I didn't created a complex structure with database, and I wanted to manage all this stuff in the template.
The thing is: how is it possible to display the right localized strings? What I thought about was to include a localized template, to separate concerns. Something like:
<!-- before the photos list -->
{% include ln ~ '/photos-list.twig' %}
<!-- then the photos list -->
And inside this template, I would have setted all the variables in the right locale, so I could use them in my photos list. (as explained in the first part of my question)
note that I have this structure for all others pages. Text content is separated in the locale folder, and each page has a master template (again, it's a very basic personal website)
What I did finally was to insert a hudge if statement before the photos list. If locale is fr, set variables with french texts, if it's en, set variables with english texts.
That does the trick, so I'm ok with that ^^
Why don't you move the second call of {{ test }} in tplB ( for this occasion ) ?
<div>Content of tpl B</div>
{% set test = "now is tpl B" %}
<p>and the variable is: {{ test }}</p>
Related
I'm using OctoberCMS and returning values from Algolia, the Twig template doesn't seem to be able to be split with the split() filter.
I have colours stored in each search item like this
["Blue_#3498db","Dark Green_#16a085","Turquoise_#06e5c7"]
As per the Algolia Instantsearch docs, my template is like this:
<script type="text/html" id="refinementListColourItem-template">
{% set itemValue = '{{value}}' %}
<div>
<a href="#">
<span>
{% set tests = itemValue|split('_') %}
{% for test in tests %}
{{ test }}
{% endfor %}
</span>
</a>
</div>
</script>
This will return the exact same string, and not split it at the underscore as expected.
The strange thing is if I manually add in one of the values like this, it works fine
{% set tests = 'Red_#c0392b'|split('_') %}
{% for test in tests %}
{{ test }}
{% endfor %}
If I dump() the variable itemValue it comes back as a string and it's not been converted to a HTML special character
I think you may be interpreting Algolia Instasearch wrong. Instasearch is a Javascript API, so the following code (as mentioned by #DarkBee in the comments) will split the string value "{{value}}". The Twig template you have in the question will return the following HTML.
<script type="text/html" id="refinementListColourItem-template">
<div>
<a href="#">
<span>
{{value}}
</span>
</a>
</div>
</script>
The above template is a valid Algolia Instasearch template. The issue is, that this is rendered before the InstaSearch API inserts your colour strings into the {{value}} part of the HMTL.
To actually achieve what you are wanting, you will actually need to use JavaScript to format the response or update your model to store the colours differently. The JavaScript (and adding ) should get you most of the way there. The code is untested and can likely be improved.
//assuming your algolia javascript variable is called search, and you have jQuery included on the page (common for OctoberCMS)
search.on('render', function() {
$(".color").each(function(){
var colour = $(this).text().split("_")[0];
$(this).text(colour); //will output first part of the text value
});
});
search.start();
Also, make the following change to your template:
<script type="text/html" id="refinementListColourItem-template">
<div>
<a href="#">
<span class="color">
{{value}}
</span>
</a>
</div>
</script>
Is this possible? I'm working on an existing website and I need to overwrite some styles but only on pages that use my new templates as overwriting the main styles might break the other pages. This is the markup:
<div id="page">
<main role="main" id="MainContent">
{{ content_for_layout }}
</main>
{% section 'footer' %}
</div>
So adding a class to the page or main element would be ideal.
I've managed to achieve this with an if statement to display content but only on a certain template, like this:
{% if template == 'page.job-detail' %}
<!-- CODE HERE -->
{% endif %}
Not sure how that'd work in relation to classes on a div? There's probably a few pages I'd need to include so an array or a way I was specify multiple templates would be ideal. Templates like "page.faq", "page.jobs", "page.job-detail".
Why don't you just add a custom class to all of your pages and target that based on the templates you like to target.
So you can add the following to the body tag.
<body class="template-{{ template | replace: '.', '-' | replace: '/', '-' }}">
And you will get classes like:
template-page-faq
template-page-jobs
template-collection
template-index
template-customer-login
etc..
From there you can use only CSS to style only what you need using the above classes.
In your template name, you can add a string that would give you a hint that it is a custom page like so,
"page.custom-faq", "page.custom-jobs", "page.custom-job-detail"
And you can do this to your HTML
<div id="page">
<main role="main" id="MainContent" class="{% if template.suffix contains 'custom' %}your-custom-class-here{% endif %}">
{{ content_for_layout }}
</main>
{% section 'footer' %}
</div>
template-{{ template | replace: '.', '-' | handle }}
Will print template-page-donate for page template with the name "donate"
I have a question: how can 1 view/page use 2 controllers to display different data?
For example:
1) Page displays DVD's information using DvdController.
2) On that same page I want to use a Template/Partial view, that displays list of actors, and that list should come from the second ActorsController.
I can add a template view inside another page but the second controller doesn't work:
MainPage on URL: website/dvd
{% block body %}
<div>
<h1>{{ dvd.title }} </h1>
</div>
<div>
{{ include('DVDBundle:Actors:actors.html.twig') }}
</div>
{% endblock %}
Above I use the partial view actors.html.twig to show the actors, strangely the html code/div's and so on are actually displayed and working on the page, however the controllers(ActorsController) method that meant to return this partial view is not executed for some reason.?
But if I go to the view directly via link: website/actors then its working.
The Symfony documentation on embedded controllers explains this nicely.
In short, you will need to do something like this in your template file:
<div>
{{ render(controller(
'DVDBundle:Actors:actors',
{ ... parameters to the controller action here ... }
)) }}
</div>
The important thing is calling the render function, which allows a controller to be rendered, as opposed to simply includeing a template. (This assumes that your have an ActorsController with an actorsAction method; change the names as appropriate to your controller.)
I use the CMS Bolt and it uses the Twig template engine. I need to access the content created in a page above where the CMS is running.
Example: Bolt installed in the blog folder; page to access and display content is the test site test/blog.
I'm using this on the page:
{% setcontent records = "entries/latest/2" allowpaging %}
{% for record in records %}
<div class="four columns thumb" style="margin-left: 0px; clear: both";>
{% if record.image!="" %}
<img src="{{ thumbnail(record.image, 100, 100) }}" alt="thumbnail" class="u-max-full-width">
{% endif %}
</div>
<div class="eight columns">
<small class="date">{{ record.datecreated|date("d.m.y") }}</small>
<p>{{ record.excerpt(75) }}</p>
</div>
{% endfor %}
I'm not sure exactly what you are trying to link to, links, theme assets etc are all handles slightly differently, however you can always navigate up from a path because the paths always print as strings...
so as well as {{paths.theme}}/images you can also do {{paths.theme}}/../images and go back a level.
equally you can go one directory up from root via {{paths.root}}/../
I have a Team to which I would like to add players (objects of Player). I've set up the form "type" classes correctly. Here's the relevant part of my view:
{% for index, player in form.players %}
<div id="template" data-prototype="{{ form_widget(form.players.get('prototype')) | e }}">
<span class="title">{{ index }}</span>
{{ form_row(player.name) }}
</div>
{% endfor %}
My problem is that data-prototype attribute doesn't include the span tag; it only contains the output of {{ form_row(player.name) }}. Is there a way to include the whole content of div#template in the data-prototype attribute?
This was bugging me too. I customized a field type and even made simple form types with a reduced fieldset (for more complex objects), but it just didn't feel right. I've come up with a solution that should do the trick :)
First - I think your <div id="team" data-prototype="..."> should be outside your loop.
Next, your prototype is just a form view object, so if you pass it to a template you can render fields by hand and customize the output. Note: autoescape has no effect on included content, so use 'filter escape'.
<div id="playerFields" data-prototype="{% filter escape %}{% include 'AcmeTeamBundle:Team:prototypePlayer.html.twig' with {'form': form.players.get('prototype')} %}{% endfilter %}">
Then in your prototypePlayer.html.twig, just render each field as you normally would in a form view.
<div>
<span class="title">{{ form_label(form.name) }}</span>
{{ form_row(form.name) }}
<span class="age">{{ form_label(form.age) }}</span>
{{ form_row(form.age) }}
{# render whatever else you like from your Form/PlayerType class... #}
<div>
My template has a different data structure to your question, but it should help :)
Cheers,
Chris
Deprecation Warning:
As of Symfony 2.1, .get() is deprecated and the above will not work. Replace form.players.get('prototype') with form.players.vars.prototype to fix this in later versions of Symfony.