twig sort not working in this situation - twig

sort does not work here
{% for key, season in seasons | sort %}
but does here
{% for episode in season | sort %}
here is the entire twig snippet
{% for key, season in seasons | sort %} {# <<this is the sort not working #}
<button class="accordion"><h5>Season {{ key }}</h5></button>
<div class="panel">
{% for episode in season | sort %}
<li><h5><b>{{ episode.title }}</b></h5></li>
{% endfor %}
</div>
{% endfor %}

If you need reverse sort use this.
{% for key, season in seasons |sort((a, b) => a.id <= b.id) %}
{% for episode in season | sort %}
{{ episode.title }}
{% endfor %}
{% endfor %}
You juste need add in your for this code.
|sort((a, b) => a.id <= b.id)

Related

Create arrays sorted on date timestamps

I'm trying to create 3 arrays of propducts which are created based on a timestamp.
I'm working on a SaaS platform so I have to create those arrays in the frontend while creating a function in the backend would be better but that's not possible.
The idea is to create 3 arrays for a lottery. So 1 is for current lotteries, 1 for upcoming ones and 1 for recent lotteries.
The problem I have is that it won't sort correctly. So for example the oputput shows 24th of april before 24th of March.
So what I have is this:
{% set curr_date = "now"| date('U') %}
{% set current_draws = [] %}
{% set upcoming_draws = [] %}
{% set recent_draws = [] %}
{% for product in products %}
{% if product.data_01 %}
{% set data_01_date = product.data_01 | date('U') %} //make timestamp for this product
{% if data_01_date > curr_date %} //check if is upcoming or current
{% if loop.first %} //if 1st in loop then it's current draw
{% set current_draws = current_draws | merge([product]) %}
{% else %}
{% set upcoming_draws = upcoming_draws | merge([product]) | sort((a, b) => a.data_01_date <=> b.data_01_date ) | reverse %}
//reverse because lowest timestamp need to be showed first
{% endif %}
{% else %}
{% set recent_draws = recent_draws | merge([ product ]) | sort((a, b) => a.data_01_date <=> b.data_01_date ) %}
{% endif %}
{% endif %}
{% endfor %}
As output for the upcoming draws array I get the following:
{% for product in upcoming_draws %}
{{ product.data_01 | date("U") }}
{% endfor %}
1648162800 // 25th March
1650751200 // 24th April
1648249200 // 26th March
1648335600 // 27th March
Why in above example is 24th of April showed before 26th of March?
Any idea how to fix that?
Any help greatly appreciated :)
Three things:
You have a typo, the property is called data_01, as seen here {% set data_01_date = product.data_01|date('U') %}
Don't sort the array during the creation of the array, that's a waste of performance
The property data_01 is a string, you shouldn't compare strings in your sort
{% set curr_date = "now"| date('U') %}
{% set current_draws = [] %}
{% set upcoming_draws = [] %}
{% set recent_draws = [] %}
{% for product in products %}
{% if product.data_01 %}
{% set data_01_date = product.data_01 | date('U') %} //make timestamp for this product
{% if data_01_date > curr_date %} //check if is upcoming or current
{% if loop.first %} //if 1st in loop then it's current draw
{% set current_draws = current_draws | merge([product]) %}
{% else %}
{% set upcoming_draws = upcoming_draws | merge([product]) %}
//reverse because lowest timestamp need to be showed first
{% endif %}
{% else %}
{% set recent_draws = recent_draws | merge([ product ]) %}
{% endif %}
{% endif %}
{% endfor %}
{% for product in upcoming_draws|sort((a, b) => a.data_01|date('U') <=> b.data_01|date('U') | reverse ) %}
{{ product.data_01 | date("d-m-Y") }}
{% endfor %}
demo

How to manipulate count based on sub-values in TWIG?

I was wondering how to manipulate / render the count based on sub-rules.
In the current situation specifications are counted and when there are more than 5, a link is shown to show more specifications. I wanted to show only specs that have a value like this:
{% for spec in product.specs | limit(5) %}
{% if spec.value %}
<li>
<span>{{ spec.title }}</span>
{{ spec.value }}
</li>
{% endif %}
{% endfor %}
{% if product.specs | length > 5 %}
<li class="more">{{ 'View all specifications' | t }}</li>
{% endif %}
In this case the count is done before checking the values of the sub-items, so the "Show more" link is visible and clickable, but doesn't show more specifications, because they are stripped out, because the value is empty but is counted as item.
The goal is to hide the "Show more" link when there are < 5 items WITH values.
I hope anyone could point me in the right direction :-)
Thank you very much for thinking with me!
You could either use an extra counter to count the valid elements,
{% for spec in product.specs | limit(5) %}
{% if spec.value %}
<li>
<span>{{ spec.title }}</span>
{{ spec.value }}
</li>
{% endif %}
{% endfor %}
{% set cnt = 0 %}
{% for spec in product.specs %}
{% if spec.value %}{% set cnt = cnt + 1 %}{% endif %}
{% endfor %}
{% if cnt >= 5 %}
<li class="more">{{ 'View all specifications' }}</li>
{% endif %}
Or you can use the filter filter
{% if products.specs| filter(spec => spec.value|default) | length >= 5 %}
<li class="more">{{ 'View all specifications' }}</li>
{% endif %}
Update as for your comment (and as you don't have access to filter)
You can't just limit the result before hand. So in the first part you would also need to use a counter
{% set cnt = 0 %}
{% for spec in product.specs %}
{% if cnt < 5 %}
{% if spec.value %}
<li>
<span>{{ spec.title }}</span>
{{ spec.value }}
</li>
{% set cnt = cnt + 1 %}
{% endif %}
{% endif %}
{% endfor %}

How to create array using Tera in Rust?

I am stuck in a simple problem but not able to figure it. I am not sure if this is the right place to ask the question on a package in Rust.
Most of the time, in the template, we will want to transform our data. For example, I wanted to concat n arrays in one line. I can use ~ operator only if I know the number of arrays.
Below is the requirement I am looking for,
{% macro generate_table(table) %}
{% for rows in 0..table.length %}
{{ table[table.col_header[0]][row] ~ " || " ~ [table.col_header[1]][row] }}
{% endfor %}
{% endmacro input %}
I want to do.
{% macro generate_table(table) %}
{% for rows in 0..table.rlength %}
{% for cols in 0..table.clength %}
{{ arr.insert(table[table.col_header[cols]][row]) }}
{% endfor %}
{{ arr | join(sep=" || ") }}
{% endfor %}
{% endmacro input %}
I figured it out. Using concat(with="")
{% macro generate_table(table) -%}
{% for row in [0,1,2] -%}
{% set_global row_val = [] -%}
{% for cols in [0,1,2] -%}
{% set_global row_val = row_val | concat(with= table.col_values[table.col_header[cols]][row]) -%}
{% endfor -%}
{{ row_val | join(sep=" ") }}
{% endfor -%}
{% endmacro generate_table -%}

Cycling through 2 objects in nunjucks

I'm using node.js and MongoDB to create an app. I have 2 collections and you could say that they are in a 1:N relation.
col1 = { id="abc", name="London", createdAt=... }
col2 = { id="..." link="abc", temperature=31.24, sentAt=... }
I would like to create a table that would display it's name and temperature (the latest one, because there could be more)
Name | Temperature
London | 31.24
So I'm passing both objects from MongoDB into nunjucks where I'm trying to cycle through them like so:
{% for city in col1 %}
{% for data in col2 %}
{{ city.name }} | {{ data.temperature }}
{% endfor %}
{% endfor %}
But if I do this the result is this:
Name | Temperature
London | 31.24
London | 31.24
And I know why that is but I don't really know how to fix it and I think that it has to have some common way to fix this.
{% set data = {} %}
{% for city in col1 %}
{% for data in col2 %}
{% set data[city.name] = data.temperature %}
{% endfor %}
{% endfor %}
{% for city, temperature in data %}
{{city}} | {{temperature}}
{% endfor %}
But the best way is uniqued values outside of nunjucks template.

Access posts from other page in jekyll pagination

Jekyll pagination enables you to arrange posts neatly on pages. I would like to put the range of dates as a tooltip on the links to the pages, just as:
<li class="pager-item">
Page 2
</li>
The obvious way to do so would be to take the date of the first and the last post on a page. Unfortunatly jekyll-pagination only seems to deliver a list of posts for the current page via paginator.posts.
Maybe I just can't find it in the documentation, so I ask you: is it possible to access a list of posts from another page in jekyll pagination? Something like paginator.pages.2.posts?
An alternate approach would be to build my own paginaton, which should be no problem, but I would prefer to use built-in functions.
You can get the information indirectly:
paginator.previous_page and paginator.next_page give you the page number of respectively the previous and the next pagination page, or nil if the page does not exists.
paginator.per_page gives you the number of posts per page.
paginator.total_posts gives you the total number of posts in the site.
site.posts gives you a reverse chronological list of all posts.
So given the current paginator object, ensuring paginator.next_page != nil, you know the posts from the next pagination page are indexed in site.posts from a to b (included) with:
a = (paginator.next_page) * paginator.per_page
b = a + paginator.per_page - 1
Last pagination page may not be complete: remember checking b < paginator.total_posts.
Ensuring paginator.previous_page != nil, same goes for previous pagination page with:
a = (paginator.previous_page) * paginator.per_page
b = a + paginator.per_page - 1
My current approach looks like this:
{% if include.page > 0 and include.page <= paginator.total_pages %}
{% assign first = include.page | minus:1 | times:paginator.per_page %}
{% assign last = paginator.per_page | times:include.page | minus:1 %}
{% if last > paginator.total_posts %}
{% assign last = paginator.total_posts | minus:1 %}
{% endif %}
{{ site.posts[first].date | date: "%d.%m.%Y" }} bis {{ site.posts[last].date | date: "%d.%m.%Y" }}
{% else %}
OUT_OF_RANGE
{% endif %}
I really don't like the Liquid-Syntax :D
Or :
{% comment %} NOTE : shortcut "p" for "paginator" {% endcomment %}
{% assign p = paginator %}
{% comment %} date formating (see shorthand formats in Ruby's documentation : http://ruby-doc.org/core-2.3.3/Time.html#method-i-strftime) {% endcomment %}
{% assign dateFormat = "%y %b %d" %}
<ul>
{% for post in p.posts %}<li>{{ post.title }} - {{ post.date | date: dateFormat }}</li>
{% endfor %}
</ul>
{% comment %}++++++++++ if previous page == newest posts {% endcomment %}
{% if paginator.previous_page %}
{% assign prevPage = p.page | minus: 1 %}
{% assign prevPageLastIndex = prevPage | times: p.per_page | minus: 1 %}
{% assign prevPageFirstIndex = prevPageLastIndex | minus: p.per_page | plus: 1 %}
{% assign prevPagefirstPostDate = site.posts[prevPageFirstIndex].date | date: dateFormat %}
{% assign prevPagenextPageLastPostDate = site.posts[prevPageLastIndex].date | date: dateFormat %}
{% capture prevPageLink %}
<p><a href="{{ paginator.previous_page_path }}"></p>
Newest posts from
{% if prevPagefirstPostDate != prevPagenextPageLastPostDate %}
{{ prevPagenextPageLastPostDate }} to {{ prevPagefirstPostDate }}
{% else %}
{{ prevPagenextPageLastPostDate }}
{% endif %}
</a>
{% endcapture %}
{% endif %}
{% comment %} ++++++++++ if next page = oldest posts {% endcomment %}
{% if paginator.next_page %}
{% assign nextPage = p.page | plus: 1 %}
{% assign nextPageFirstIndex = p.page | times: p.per_page %}
{% comment %}>>Next page is not the last page = normal computing {% endcomment %}
{% if nextPage != p.total_pages %}
{% assign nextPageLastIndex = nextPageFirstIndex | plus: p.per_page | minus: 1 %}
{% comment %}>>Next page is the last page compute index from p.total_posts{% endcomment %}
{% else %}
{% assign nextPageLastIndex = p.total_posts | minus: 1 %}
{% endif %}
{% assign nextPagefirstPostDate = site.posts[nextPageFirstIndex].date | date: dateFormat %}
{% assign nextPageLastPostDate = site.posts[nextPageLastIndex].date | date: dateFormat %}
{% capture nextPageLink %}
<p><a href="{{ paginator.next_page_path }}"></p>
Previous posts from
{% if nextPagefirstPostDate != nextPageLastPostDate %}
{{ nextPageLastPostDate }} to {{ nextPagefirstPostDate }}
{% else %}
{{ nextPageLastPostDate }}
{% endif %}
</a>
{% endcapture %}
{% endif %}
{{ prevPageLink }}
{{ nextPageLink }}

Resources