ht-each directive reference

Overview


The ht-each directive repeats the target HTML element once per occurrence of some template data.

When combined with template variables and other templating directives such as ht-include, ht-if, and ht-attrs, the ht-each directive is a powerful building block for defining dynamic layouts that adapt to the contents of template data.

Example


This example shows the ht-each directive being used to template navigation links in a <header> element.

layout.html
 1<html lang='en-US'>
 2    <head>
 3        <meta charset='utf-8'>
 4        <title>Hello, world</title>
 5        <meta name='description' content='ht-each directive reference'>
 6    </head>
 7    <body>
 8        <header>
 9            <nav>
10                <menu>
11                    <a ht-each='link in ${ data.nav }' href='${ link.href }'>
12                        ${ link.title, link.label, "Placeholder" }
13                    </a>
14                </menu>
15            </nav>
16            <h1>ht-each</h1>
17        </header>
18        <main>
19            <h2><code>ht-each</code> directive reference</h2>
20            <p>...</p>
21        </main>
22    </body>
23</html>
Example output index.html

Let's see what happens when we process this template with the following template data.

 1{
 2    data: {
 3        nav: [
 4            { label: "Home", href: "/" },
 5            { label: "Features", href: "/features/" },
 6            { label: "Docs", href: "/docs/" },
 7            { label: "Blog", href: "/blog/" },
 8        ]
 9    }
10}

The placeholder template <a> element will be cloned once for each item in the data.nav template data property (an object array). The end result should be four (4) <a> elements dynamically generated by HyperTemplates.

 1<html lang='en-US'>
 2    <head>
 3        <meta charset='utf-8'>
 4        <title>Hello, world</title>
 5        <meta name='description' content='ht-each directive reference'>
 6    </head>
 7    <body>
 8        <header>
 9            <nav>
10                <menu>
11                    <a href='/'>Home</a>
12                    <a href='/features/'>Features</a>
13                    <a href='/docs/'>Docs</a>
14                    <a href='/blog/'>Blog</a>
15                </menu>
16            </nav>
17            <h1>ht-each</h1>
18        </header>
19        <main>
20            <h2><code>ht-each</code> directive reference</h2>
21            <p>...</p>
22        </main>
23    </body>
24</html>

Specification


Supported elements


The ht-each directive can be used with any HTML element, including void elements.

1<meta ht-each='property in ${ page.metadata }' name='${ property.name }' content='${ property.value }' />

Directive syntax


The ht-each directive defines iteration expressions using the binding in ${ variable } syntax.

The binding is a name assigned to a template data property that will be passed into the nested template.

The variable is a template variable that returns a template data property.

1<a ht-each='link in ${ data.nav }' href='${ link.href }'>

In this example, the link variable will be added to the template data that gets passed in to the nested <a> template.

Template data


Three auto-generated template data properties are available during ht-each iteration:

  • each.index a one-indexed integer representing the position in the loop
  • each.count the count of items in the iteration window (after ht-offset and ht-limit are applied)
  • each.total the total count of items in the collection

Placeholder template


An HTML element with an ht-each directive is called an "placeholder template". Placeholder and their child elements (if any) are cloned once per iteration of the referenced template data value.

fragments/nav.html
1<nav>
2    <a ht-each='link in ${ data.nav }' href='${ link.href }'>
3        ${ link.label, "Placeholder" }
4    </a>
5</nav>

In this example, the <a> element together with its child ${ link.label, "Placeholder" } text node make up an iterator template.

Limit and offset


The ht-limit and ht-offset directives can be used to configure partial iterators. Use ht-limit to limit the number of elements generated by an ht-each iterator. Use ht-offset to skip the first n items in the ht-each template data.

The following example shows how to configure a feed page with three "featured posts", followed by any remaining posts. Both blocks are using the same page.feed.pages template data.

 1<!-- Blog posts fragment -->
 2<section id='blog'>
 3    <style>
 4        featured-posts {
 5            display: grid;
 6            grid-auto-flow: column;
 7            grid-template-columns: 1fr 1fr 1fr;
 8        }
 9        recent-posts {
10            display: grid;
11            grid-auto-flow: row;
12            grid-template-columns: 1fr;
13        }
14    </style>
15    <featured-posts>
16        <a ht-each='post in ${ page.feed.pages }' ht-limit='3' href='${ post.href }'>
17            <!-- Featured Post Layout -->
18        </a>
19    </featured-posts>
20    <recent-posts>
21        <a ht-each='post in ${ page.feed.pages }' ht-offset='3' href='${ post.href }'>
22            <!-- Recent Post Layout -->
23        </a>
24    </recent-posts>
25</section>

If the recent posts block should be further constrained to show a limited number of items, the ht-limit directive could be used alongside ht-offset.

1<recent-posts>
2    <a ht-each='post in ${ page.feed.pages }' ht-offset='3' ht-limit='6' href='${ post.href }'>
3        <!-- Recent Post Layout -->
4    </a>
5</recent-posts>

NOTE: ht-limit is always applied as a count, not a range. The equivalent Javascript is an Array.slice() expression of arr.slice(offset, offset+limit). In the example above that would be arr.slice(3, 3+6) (up to 6 items), not arr.slice(3, 6) (up to 3 items).

💬 Join the community

Stay up-to-date with the latest releases and other news from the Team behind HyperTemplates. Ask the developers questions, get help from the community, and share your creations! 🎨