Range index to catch first item (and last)

The way I understand the range function the following should add a class “first” for the first item of a range:

  {{ range $index, where $paginator.Pages "Params.hidden" "ne" "true" }}
  <article class="{{ if (eq $index 0) }}first{{ end }}">

It doesn’t though :wink: I tried adding "0" instead of 0 - same result. Where am I thinking wrong?

Also, is there some kind of length function that can tell me if I am at the last $index item?

When you use range, you can use either zero, one or two variables within your loop. Because we are in a list (and not a dictionary), our indexes are numbers

Each item in the loop has an index and value. In this case, the index is a number and the corresponding value is a page object.

  • zero: range where… then the context (.) is the value
  • one: range $value, where… or range $value := where then you get the value (not the index) within the variable
  • two: range $index, $value := where… then you have both the index and the value

This snippet works:

{{ range $index, $value := where $.Paginator.Pages "Params.hidden" "ne" "true" }}
        <article class="{{ if (eq $index 0) }}first{{ end }}"></article>
{{ end }}

However, what you’re trying to achieve here through templating can (and imho should) be achieved directly in CSS with selectors : first-child… There’s plenty more you should check out :slight_smile:

So for example here, assuming we have a <main> container around the articles, we could just write:

main article:first-child {
    …
}

But maybe you have your other reasons to want a “first” class on the first article :wink:

3 Likes

For the first should work.

{{ if not $index }}first{{ end }}

Why doesn’t something like this work? First/Last

{{ range last 10 .Data.Pages }}
    {{ .Render "summary" }}
{{ end }}

You are right, this specific case would be easily solved by using CSS. But if for instance I want to show only titles from the second item on instead of title/content I would need an $index item. Good to know this way.

Everything from “Each item…” to the end of the three bullet points should be part of the documentation IMHO. Just saying. That explained it all.

The range itself works, but I want to catch first/last items, or even indexed items.

1 Like

Well it depends. If you want the content to be fully stripped from the HTML, then you need some templating logic like mentioned before. But if you simply want to make the content invisible to the end-user then it can be easily achieved in CSS.

I guess that depends on the actual content. If we’re talking text summary, then simply hiding it is fine. But if you’re loading the whole article (including pictures) in your list templates, then templating logic to strip that HTML would make the page load way faster.

Assuming your content is in a “content” class div:

main article:not(:first-child) .content {
    display: none;
}

CSS3 selectors are very very powerful I would advise you to take a deep look at them as they allow to very efficiently do what 99% of webdevs would do with some ugly JavaScript hack.

Old post but nobody mentioned here how to check for the last:
{{ if eq (add $i 1) (len $paginator.Pages) }}

Or easily switch this to use the not equal ne check which will loop all apart from the last:
{{ if ne (add $i 1) (len $paginator.Pages) }}