How to range every n items at a time


#1

Hi!

I was wondering if it’s possible to add 1 to the range index, so next iteration starts skipping one element of the list.

Let me explain myself, I want to loop through my pages and display in a css column two of them, after another 2 in the next column. In order to do this I’m trying :

{{ range $i := .Paginator.Pages }}
    <div class="columns">
       <div class="column is-half">
          <h1 class="title"><a href="{{ .Permalink }}">{{ .Title }}</a>{{ if .Draft }} ::Draft{{ end }}</h1>
          <div class="content">
             {{ .Summary | plainify | safeHTML }}
           </div>
         </div>

       <div class="column is-half">
          <h1 class="title"><a href="{{ .Next.Permalink }}">{{ .Next.Title }}</a>{{ if .Next.Draft }} ::Draft{{ end }}</h1>
          <div class="content">
             {{ .Next.Summary | plainify | safeHTML }}
           </div>
         </div>
    </div>
{{ add $i 1 }}
{{ end }}

The problem is that I get repeated content because .Next in the first iteration is . in the second one.

Is there a way to skip a element ?


#2

Maybe try an if statement and if the index number matches “1” you skip it?

I faced a similar problem and at some point I decided to just live with it.


#3

Done that too for iterating over CSV file for the first line. Works like a charm if you can deal with a {{ if $i eq 0 }}


#4

but that only fixes the problem for the first two items no? If I have 10 pages I will still have duplicates after the 3rd one.


#5

Try the mod math function.


#6

Not sure if this is the best way, but I had a little go ranging over a section and displaying every other one. Here is the code, in case this helps. You will have to adapt for your purposes, but the principle is there:

{{ $.Scratch.Set "counter" 0}}
{{ range first 10 (where .Site.Pages "Type" "in" (slice "contenttype" )) }}
{{ $counter := $.Scratch.Get "counter" }}
{{ if eq $counter 0 }}
<a href="{{.Permalink}}">{{.Title}}</a>
{{ $.Scratch.Add "counter" 1}}
{{else}}
{{ $.Scratch.Add "counter" -1}}
{{ end }}
{{ end }}

Obviously, if you set the range to first 10, only 5 entries will show. To get the missing items just move the .Title to the Else statement.

I know this doesn’t necessarily solve your problem, but hopefully it might put you in the right direction or give you some ideas. I re-read your problem, and may give it some further thought later.


#7

Try this. I have kind of tested on my site, but you will need to test it yourself and check it is behaving as required, and adapt as necessary.


{{ $.Scratch.Set "counter" 0}}
{{ $.Scratch.Set "counter2" 0}}
{{ $paginator := .Paginate (where .Site.Pages "Type" "in" (slice "news")) }}

<div class="columns">
    <div class="column is-half">
        {{ range $paginator.Pages }}
        {{ $counter := $.Scratch.Get "counter" }}
        {{ if eq $counter 0 }}
        <h1 class="title"><a href="{{ .Permalink }}">{{ .Title }}</a>{{ if .Draft }} ::Draft{{ end }}</h1>
        <div class="content">
            {{ .Summary | plainify | safeHTML }}
        </div>
        {{ $.Scratch.Add "counter" 1}}
        {{else}}
        {{ $.Scratch.Add "counter" -1}}
        {{ end }}
        {{ end }}
    </div>

    <div class="column is-half">
        {{ range $paginator.Pages }}
        {{ $counter2 := $.Scratch.Get "counter2" }}
        {{ if eq $counter2 0 }}
        {{ $.Scratch.Add "counter2" 1}}
        {{else}}
        <h1 class="title"><a href="{{ .Permalink }}">{{ .Title }}</a>{{ if .Draft }} ::Draft{{ end }}</h1>
        <div class="content">
            {{ .Summary | plainify | safeHTML }}
        </div>
        {{ $.Scratch.Add "counter2" -1}}
        {{ end }}
        {{ end }}
    </div>
</div>

{{ partial "pagination.html" . }}

Edit: I think this works better:

{{ $.Scratch.Set "counter" 0}}
{{ $paginator := .Paginate (where .Site.Pages "Type" "in" (slice "news")) }}
<div class="row">
    {{ range $paginator.Pages }}
    {{ $counter := $.Scratch.Get "counter" }}
    {{ if eq $counter 0 }}
    <div class="column is-half">
        <h1 class="title"><a href="{{ .Permalink }}">1{{ .Title }}</a>{{ if .Draft }} ::Draft{{ end }}</h1>
        <div class="content">
            {{ .Summary | plainify | safeHTML }}
        </div>
        {{ $.Scratch.Add "counter" 1}}
    </div>
    {{else}}
    <div class="column is-half">
        <h1 class="title"><a href="{{ .Permalink }}">2{{ .Title }}</a>{{ if .Draft }} ::Draft{{ end }}</h1>
        <div class="content">
            {{ .Summary | plainify | safeHTML }}
        </div>
    </div>
    {{ $.Scratch.Add "counter" -1}}{{ end }}
    {{ end }}
</div>
{{ partial "pagination.html" . }}

But the above example is the same as:


{{ $paginator := .Paginate (where .Site.Pages "Type" "in" (slice "news")) }}
<div class="row">
    {{ range $paginator.Pages }}
    <div class="column is-half">
        <h1 class="title"><a href="{{ .Permalink }}">1{{ .Title }}</a>{{ if .Draft }} ::Draft{{ end }}</h1>
        <div class="content">
            {{ .Summary | plainify | safeHTML }}
        </div>
    </div>
    {{ end }}
</div>
{{ partial "pagination.html" . }}

Am I missing something?

I feel like I am misunderstanding what you are trying to achieve, or the answer is more simple than I thought.


#8

I’ll try to explain better. I’m trying to make a a 2 by n grid with all pages of certain type in a list view. Just like the screenshot:

But as you can see, every item is duplicated on each row (because both boxes are created in the same loop iteration) I would like to avoid duplication and achieve that grid.


#9

So if I understand, you’re trying to get articles ordered like so:

1 2
3 4
5 6

Is that correct? There’s many ways to achieve this. The most obvious starting from your code, would be to define your <div class="columns"> outside of the item (more in the list template). This way you could just write:

{{ range $i := .Paginator.Pages }}
  <div class="column is-half">
    <h1 class="title"><a href="{{ .Permalink }}">{{ .Title }}</a>{{ if .Draft }} ::Draft{{ end }}</h1>
    <div class="content">
         {{ .Summary | plainify | safeHTML }}
    </div>
  </div>
{{ end }}

The next article will also be in the columns, but if your is-half does the job, your articles should just fit to their place because 50% + 50% = 100% means you’ll get two is-half per line in your columns. (the width of an element within a container is relative to the parent container’s width)

Two less obvious options which give way for exploration:

  1. Some CSS selectors like so : article:nth-of-type(odd) and article:nth-of-type(even) to do your work.
  2. CSS grid with a grid-template-area generated on the fly. I’m using this to generate a responsive multi-column layout directly from a partial call :slight_smile:

So I hope to have made it clear that, at least to me, this looks like a simple webdesign issue that has nothing to do with templating. You could literally take your raw HTML and CSS without hugo and debug this out on your desktop! :sunglasses:

Good luck and let us know if you need more help!


#10

That is, indeed correct. I tried several nesting option, including what you suggest, but I don’t get the desired output, just a really long row or column, an example:

So maybe is a css problem, the theme is using bulma css so I was assuming that would be correct.

Thanks for you answer :slight_smile: This is driving me a little bit crazy.


#11

Well if you point me to your sources (or the actual site), i will be glad to help you debug it out.

However, in the meantime, it looks like is-half is not width: 50%;, or maybe there’s some overflow happening outside of your columns. Can you try opening Firefox’s inspector and see what the actual applied CSS properties are?


#12

Sure, that’s the page -> https://plorenzo.es/listas/

Looks like width is 50%


#13

Okay so your content is overflowing. That means it’s for some reason not going to the new line when the end of the box is met. You can see it because the container size is just two columns, but the rest is displayed as well. Applying a overflow:hidden; on columns will show you what I mean :slight_smile:

I figured it out from the Bulma docs about columns that if you want a multiline column, you need to add the is-multiline class to your columns container.

Does that help?


#14

:heart::heart::heart:

It does help!! Thank you very much :tada:


#15

You’re welcome :slight_smile: