Access to collection elements using a numerical index

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:

{% 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.

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?

{% 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.

What do you get for

{{debug(i)}}
{{debug(collection1)}}
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:

{% 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.

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

{{debug(collection1.toArray)}}

or is it

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

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

{{debug(collection1.toArray)}}

result:

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"
  ]
]```

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

This looks like a numerically indexed array to me that you could use [n] on.

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

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

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

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

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

result:

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

and if:

{% set keys1 = collection1|keys %}

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

result:

Lorem ipsum (title)

:slight_smile:

Thank you Karmalakas!

1 Like

I know you have numerical slugs (confusing!) but I think you’re right anyway, the formatting is misleading.

1 Like

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

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

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