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>
Related
I'm trying in my code to build a list of courses in an html file (using twig) - but the thing is - I need to use it twice.
Once to get the list (and that obviously worked), and once to create a form with multiple checkboxes running in another for loop.
I read that the 'unset' function can fix this problem - but it says in doesn't exist in Twig.
here's my code:
{% for course in courses %}
<a href="/course/{{course.id}}">
<div id="info-box">
<img src="/views/{{course.image_link}}" alt="" width=95>
<p style="margin-left: 1rem;">{{course.name}}</p>
</div>
</a>
{% endfor %}
and then I need to write a form:
<form>
{% for course in courses %}
<input type="checkbox" name="course" value={{course.id}}>{{course.name}}
{% endfor %}
</form>
The second loop doesn't work.
I'd love for some help please! :)
and the courses variable comes from a different index file that sends it to an html file.
I'm not sure why u only can use twig as it would be better to fetch the result in actual array than rather passing the PDOStatement.
The reason u can only foreach the collection once is because PDOStament is a forward-only result set. This means you can only get the data from this object once.
To resolve this issue in twig this would mean u need to build an array first and then use that array to display your html
{% set courses_array = [] %}
{% for course in courses %}
{% set courses_array = courses_array | merge([course]) %}
{% endfor %}
It sure is better to do this in PHP, rather then in twig
<?php
$stmt = $pdo->prepare('SELECT * FROM courses');
$stmt->execute();
$courses = $stmt->fetchAll(PDO::FETCH_ASSOC);
$twig->render('courses.twig', [ 'courses' => $courses, ]);
Another solution would be to do the fetch inside twig, to access a constant you can use the function constant
{% set courses_array = courses.fetchAll(constant('PDO::FETCH_ASSOC')) %}
note: I did not test the last solution
I am using an already made template and now I am having problems when I am trying to display a set of products with descriptions...
All of the products have different descriptions and If one products has more text, its thumbnail is larger, thus it makes the product list look terrible..
This is the thumbnail:
<ul class="thumbnails">
{% for item in pagination %}
<li class="span3">
<div class="thumbnail">
<div class="caption">
<p>
<span>{{ entry.shortDescription|raw }}</span>
</p>
</div>
</div>
</li>
{% endfor %}
</ul>
Now how to make this work, for example I want to add only the first 200 letters form all of the products... Is that possible to do from a twig?
Yes it is, but I would definitely do it by using a twig filter, which would truncate the description string. You have a set of twig extensions you can add to your application: http://twig.sensiolabs.org/doc/extensions/index.html . Specifically, look at the "Text" extension and it's truncate filter
I'm building a themed view in Drupal 8 using twig. I'd like to use twig filters on the row.content variable in the views-view-unformatted.html.twig template.
It seems that row.content is an array so twig's string manipulation doesn't work. However, it prints onto the page as a string (view is just a list of taxonomy terms).
What I'd like to do is slugify the output so taxonomy terms with spaces can have valid hrefs. See the replace filter in the code below.
<ul class="nav nav-tabs" role="tablist">
{% for row in rows %}
<li role="presentation" class="{{loop.first ? 'active' : ''}}">
{{row.content}}
</li>
{% endfor %}
</ul>
This will just output <a href="#">. Does anyone know how to access the raw text value that is output during twigs interpolation?
Thanks!
I ran into this myself it was difficult because kint and dump crashes on views.
there is a quick workaround to get to the bits though, put this under {% for row in rows %} in your twig views style template.
<ol>
{% for key, value in row.content %}
<li>{{ key }}</li>
{% endfor %}
</ol>
load the page with that & gives you the keys to see, I checked them each with the following dump command, just added underneath to test.
{{ dump(row.content['#row']) }}
The above dump showed all the goods in #row, where I dug in and found the field I wanted inside _entity (may be different for you), then I wanted to replace spaces with dash and force lowercase.
Everything past row.content['#row'] is likely different for you, you'll need to dig in the array a bit with the dump command mentioned above.
Below is the line that got me what I wanted.
{{ row.content['#row']._entity.title[0].value|replace(' ', '-')|lower }}
Below is twig template example.
For filename change viewname and block-3 to your setup.
views-view-unformatted--viewname--block-3.html.twig
{% for row in rows %}
{%
set row_classes = [
default_row_class ? 'views-row',
'something',
'kint-cant',
]
%}
{# My field value unformatted #}
<!-- {{ row.content['#row']._entity.title[0].value }} -->
<section{{ row.attributes.addClass(row_classes) }} id="{{ row.content['#row']._entity.title[0].value|replace(' ', '-')|lower }}">
{{ row.content }}
</section>
{% endfor %}
Im sure there are plenty of other ways to do this, but it worked for me as a quick solution to print out views fields in the style template, which is really useful.
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>
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.