Skip to content
Grav 2.0 is officially stable. Read the announcement →
Support

Access to collection elements using a numerical index

Solved by Karmalakas View solution

Started by Norbert 3 years ago · 13 replies · 683 views
3 years ago

I have two collections: collection1, collection2.

Based on them, I want to generate an HTML table in which the first column will be the first element of the collection1 array, and the second column will contain the first element of the collection2 array.

So I have the html.twig code:

TWIG
{% set collection1 = page.collection %}
{% set collection2 = page.collection('nabor2') %}
{% set max_length = max(collection1|length, collection2|length) %}

<table class="table">
  {% for i in 0..max_length-1 %}
    <tr>
      <td>{{collection1[i].title}}</td>
      <td>{{collection2[i].title}}</td>
    </tr>
  {% endfor %}
</table>

But it doesn't work.

3 years ago

If you defined doesn’t work more clearly, it would be much easier to help. What happens? Do you get an error? Do you get no output at all?

3 years ago
TWIG
{% for i in 0..max_length-1 %}
    {{debug(collection1[i])}}
{% endfor %}

I get null in the console. However, the collection1 exists and contains many elements.

3 years ago

What do you get for

TWIG
{{debug(i)}}
{{debug(collection1)}}
3 years ago
TXT
0
debugGrav\Common\Page\Collection {#2500 #pages: Grav\Common\Page\Pages {#170 -directory: null #...
1
debugGrav\Common\Page\Collection {#2500 #pages: Grav\Common\Page\Pages {#170 -directory: null #...

and more results of this scheme.

However, if I make a classic loop to display the content, it obviously works:

TWIG
{% for item in collection1 %}
    {{debug(item.title)}}
{% endfor %}

and as a result I get a list of titles.

I understand that a collection object is not an array. However, I don't know how to iteratively access each element, considering that in the view I have to match the first element of collection collection1 with the first element of collection2, etc.

last edited 11/29/23 by Norbert
3 years ago

So you see your collection1 is not an array. You can't just access its elements by index. What's the result of

TWIG
{{debug(collection1.toArray)}}

or is it

TWIG
{{debug(collection1.toArray())}}
{{debug(collection1|toArray)}}

I don't remember the syntax and not at my PC now

3 years ago
TWIG
{{debug(collection1.toArray)}}

result:

TXT

array:23 [
  "/home/norbert/www/czystepowietrze/user/pages/07.inne-programy/03.cieple-mieszkanie/14.pytania-i-odpowiedzi/01.beneficjent-koncowy/01.1-nabor/1" => array:1 [
    "slug" => "1"
  ]
  "/home/norbert/www/czystepowietrze/user/pages/07.inne-programy/03.cieple-mieszkanie/14.pytania-i-odpowiedzi/01.beneficjent-koncowy/01.1-nabor/2" => array:1 [
    "slug" => "2"
  ]
]```
1 reply
last edited 11/29/23 by Norbert
3 years ago Solution

Do you have title if you use toExtendedArray?
In any case, I see keys are as paths in the converted array, so you'd need to convert it to indexed array. In PHP there's array_values function, but I don't see this in Twig. You could try .toExtendedArray.array_values, but might not work. In such case I'd probably do a bit differently - do two loops to construct your arrays with titles from your collections and then a third loop like you did initially

3 years ago

Wouldn't Twig's slice filter work on the original page collection? Like collection1|slice(n,1)?

3 years ago Hugh Barnes @q3d: array:23 [ This looks like a numerically indexed array to me that you could use [n]…

@hughbris:
This looks like a numerically indexed array to me

I believe it's not. It's just a count I assume.

JS
[
  "path/1" => ["slug" => "1"],
  "path/2" => ["slug" => "2"],
  // 21 more items here
]

@hughbris:
Wouldn’t Twig’s slice filter work on the original page collection? Like collection1|slice(n,1)?

If slice doesn't work by reference and leaves the actual collection1 intact, then I suppose it might work

1 reply
3 years ago

{% set collection1 = page.collection.toExtendedArray %}

result:

PHP
array:2 [
  "header" = array:2 [
    "title" = "Lorem ipsum (title)"
    "simplesearch" = array:1 [
      "process" = false
    ]
  ]
  "content" = "Lorem ipsum dolor"
]

and if:

TWIG
{% set keys1 = collection1|keys %}

{{debug(collection1[keys1[0]].header.title)}}

result:

TXT
Lorem ipsum (title)

:)

Thank you Karmalakas!

👍 1
last edited 11/29/23 by Norbert
3 years ago

A collection is not indexed by int, but by string (path of page).

An alternative to Collection::toExtendedArray() could be:

TWIG
{% set collection1 = page.collection %}
{% set paths1 = collection1.toArray|keys %}

{% set collection2 = page.collection('content2') %}
{% set paths2 = collection2.toArray|keys %}

{% set max_length = max(collection1|length, collection2|length) %}

<table class="table">
{% for i in 0..max_length-1 %}
    <tr>
    <td>{{collection1[paths1[i]].title}}</td>
    <td>{{collection2[paths2[i]].title}}</td>
    </tr>
{% endfor %}
</table>

Note: collection1.offsetGet(paths1[i]) could also be used

last edited 11/29/23 by pamtbaau

Suggested topics

Topic Participants Replies Views Activity
Support · by Anna, 24 hours ago
2 72 3 hours ago
Support · by gtx, 1 week ago
4 234 2 days ago
Support · by Paul Hodges, 2 weeks ago
13 283 5 days ago
Support · by Anna, 3 weeks ago
9 340 1 week ago
Support · by TomW, 2 weeks ago
4 192 2 weeks ago