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

Specify individual children in collection?

Started by Muut Archive 10 years ago · 6 replies · 552 views
10 years ago

I feel like there should be an easy way to do this, but I can't find it. I need specifically chose a child from a collection while looping through the collection. The order doesn't really matter, just as long as I can pick say the nth child in the collection wherever I need it and place it where I want to. I guess I don't even need to loop through the collection. I just need to select each child specifically. I'm aware of

TXT
loop.first and loop.last
--- 
but what about children in-between the first and last?

I have a page that needs to show each child in a portfolio of items, but each item is not formatted the same way. The general layout is 

<div class="style1">
<img src="image1.jpg">
<a href="/path/to/first/item/"
</div>
<div class="style2">
<img src="image2.jpg">
<a href="/path/to/second/item/"
</div>
<div class="style3">
<img src="image3.jpg">
<a href="/path/to/third/item/"
</div>

TXT
And so on. I can't just iterate over the entire collection because I need the first child to be in "style1", the second child in "style2" and so on. I tried

{% for child in collection %}
{% if loop.first %}
<div class="style1">
<img src="{{ child.media.image|first.url }}">
<a href="{{ child.url }}"
</div>
{% endif %}
<div class="style2">
<img src="image2.jpg">
<a href="/path/to/second/item/"
</div>
<div class="style3">
<img src="image3.jpg">
<a href="/path/to/third/item/"
</div>
{% endfor %}

TXT
which works for the first child, but no others. I tried other things like 

{% set first_child = collection[1:1] %} and {% set first_child = collection|slice(0,1) %}

TXT

to no avail. Any thoughts?
10 years ago

I found one solution, although I'm not sure if this is the best way to go about it.

TWIG
{% for child in collection|sort %}
   {% if loop.revindex == 1 %}
      <div class="style1">
         <img src="{{ child.media.image|first.url }}">
         <a href="{{ child.url }}"
      </div>
   {% elseif loop.revindex == 2 %}
      <div class="style2">
         <img src="image2.jpg">
         <a href="/path/to/second/item/"
      </div>
   {% elseif loop.revindex == 3 %}
      <div class="style3">
         <img src="image3.jpg">
         <a href="/path/to/third/item/"
      </div>
   {% endif %}
{% endfor %}

Hopefully anyone else who had this problem can see this and start from here.

10 years ago

Your solution seems like the best way to me, although I think something like this might work if your class name is actually style 1, style 2, style 3 etc.:

TWIG
{% for child in collection|sort %}
      <div class="style{{ loop.index }}">
         <img src="{{ child.media.image|first.url }}">
         <a href="{{ child.url }}"
      </div>
{% endfor %}
10 years ago

Your solution is one step better even. Although I'd have to change a few things in the CSS. Cheers.

10 years ago

Maybe the best way would be to specify a variable in the header with options like 'size1, size2, size3' and then your code would be :

TWIG
{% for child in collection|sort %}
      <div class="{{ child.header.mydivsize }}">
         <img src="{{ child.media.image|first.url }}">
         <a href="{{ child.url }}"
      </div>
{% endfor %}

or if your child elements displayed does not have the same structure, you must keep your solutions like below.

TWIG
{% for child in collection|sort %}
   {% if child.header.mydivsize == "size1" %}
      <div class="style1">
         <img src="{{ child.media.image|first.url }}">
         <a href="{{ child.url }}"
      </div>
   {% elseif child.header.mydivsize == "size2" %} 
      <div class="style2">
         <img src="{{ child.media.image|first.url }}">
         <a href="{{ child.url }}"
      </div>
  {% elseif child.header.mydivsize == "size3" %}
      <div class="style3">
         <img src="{{ child.media.image|first.url }}">
         <a href="{{ child.url }}"
      </div>
   {% endif %}
{% endfor %}

If you have more than a few 'size types', (let's say a dozen), then maybe you should probably use an array.

10 years ago

The issue with my layout is I actually have it in this format

HTML
<div class="boxA">
   <div class="style1">
      <img src="image1.jpg">
      <a href="/path/to/first/item/"
   </div>
   <div class="style2">
      <img src="image2.jpg">
      <a href="/path/to/second/item/"
   </div>
   <div class="style3">
      <img src="image3.jpg">
      <a href="/path/to/third/item/"
   </div>
</div>
<div class="boxB">
   <div class="style4">
      <img src="image4.jpg">
      <a href="/path/to/fourth/item/"
   </div>
   <div class="style5"> 
      <img src="image5.jpg">
      <a href="/path/to/fifth/item/"
   </div>
   <div class="style6">
      <img src="image6.jpg">
      <a href="/path/to/sixth/item/"
   </div>
</div>

I didn't add it before because it would confuse and bloat things. But the layout looks sweet. It's a website I made earlier in the year that I'm porting to grav. But it makes this process a bit tedious.

Your first solution is better for me because I can specify the exact spot where I want each item to go straight in the header. I'm going to try and implement this

TWIG
{% for child in collection|sort %}
      <div class="{{ child.header.mydivsize }}">
         <img src="{{ child.media.image|first.url }}">
         <a href="{{ child.url }}"
      </div>
{% endfor %}

With two for loops in each "box" div. Should work nicely, and it's more efficient than my solution. Thank you for your help.

10 years ago
TXT
.wrapper.highlight2 .child:nth-of-type(2) { position: absolute; etc…}
.wrapper.highlight3 .child:nth-of-type(3) { position: absolute; etc…}
.wrapper.highlight4 .child:nth-of-type(4) { position: absolute; etc…}
.wrapper.highlight5 .child:nth-of-type(5) { position: absolute; etc…}

If you wrap the whole collection in a parent div, you can change the position of a child element with css by changing a class on the parent. You can then just class="wrapper highlight{{ num-to-highlight }}" in your template and you can change it client side too with a little javascript.

The position absolute pulls that item out of the DOM flow so the items after it should just slide up.

Suggested topics

Topic Participants Replies Views Activity
Archive · by Deleted User, 9 years ago
0 1368 9 years ago
Archive · by Muut Archive, 9 years ago
2 940 9 years ago
Archive · by Muut Archive, 9 years ago
2 4069 9 years ago
Archive · by Muut Archive, 9 years ago
1 2960 9 years ago
Archive · by Muut Archive, 9 years ago
3 1125 9 years ago