Trio Icon
Trio v6.0.3
Documentation is evolving and is a WIP

Collections

Introduced in v2.0.0

Collections are groups of pages that are dynamically generated by Trio that you would otherwise have to manually create yourself.

As an example, let's imagine that you have a team website which includes a page that lists all the team members. Information about each team member is maintained in a file named root/source/data/team.json. You would now like to create a detail page for every team member and render those pages when someone clicks on one of the team members in the list.

Without collections, you would have to manually create one fragment for each team member's detail page. If there are only a few team members then that wouldn't be too difficult. Suppose, however, there are dozens of, if not more, team members and how tedious it would be to have to manually create and maintain all those fragments.

That's where collections come to the rescue; they do all the "heavy lifting" for you. You only need to create one fragment whose front matter declares one collection filter function that when called by Trio returns a collection dataset, which is an array that contains one collection dataset item for each member of the team. Trio will then create a "clone" of that fragment in memory for every collection dataset item and will expose the collection dataset item's properties for that cloned fragment to tag-based callbacks via the callback's asset argument, specifically as the asset.collection.data property.

Implementing Collection Fragments

To create a collection, add a collection hash to a fragment's front matter and assign its filterFn property the name of a filter function located in the /source/filters folder.

<!--
template: default
title: Member |
appendToTarget: true
collection:
    filterFn: member
-->

<div data-trio-callback="teamMember">
    <h1><u>Team Member</u></h1>
    <h2 id="name">Name: </h2>
    <h2 id="title">Title: </h2>
    <p id="bio"></p>
</div>

<a href="/">Main Page</a>
Example: Fragment Used To Generate A Collection

You can also add custom properties to the collection hash which will be accessible in your collection's filter function.

Fragments that declare collections in their front matter are always treated as stale and therefore do not need to be marked with alwaysBuild.

Collection Datasets

Collection datasets are arrays of collection dataset items that collection filter functions return. Each collection dataset item in a collection dataset represents a single page of the collection. The total number of collection dataset items in a collection dataset determines the total number of pages that Trio will generate for the collection.

Collection Dataset Item Properties

Each collection dataset item in a collection dataset must include the following properties:

pageName

The name that will be used for the page, which may also include a path.

Trio uses the value that you assign to pageName for generating the path in the root/source/fragments/ folder that the "cloned" fragment would be located in if it were actually written to disk. This allows Trio to treat the in memory only "cloned" fragment as if it actually was a physical file.

Trio uses the following algorithm to generate the path: path to the fragment in which the collection is declared + collectionDatasetItem.pageName + the file name extension of the fragment (either .html or .md) in which the collection is declared.

data

The data that is intended to be exposed to the composite's tag-based callbacks, which can be accessed to add dynamic content to the page. Using the team website for an example, the data property would be assigned a single item from the root/source/data/team.json file.

Prior to v3, you were able to name this property anything as long as it adhered to JavaScript's object property naming conventions. However, this ambiguity prevented Trio from validating each dataset item. To remedy this, beginning with v3, Trio requires that this must now be named "data".

You can use any of the data that is exposed by the metadata site object.

You can add your own custom properties to collection dataset items and they will be accessible in the composite's tag-based callbacks also.

Implementing Collection Filter Functions

Each module must export a single function which, when called by Trio, is passed a single argument

{ collection, site }

which can be destructured (see Unpacking fields from objects passed as function parameter for more information)

({ collection, site })

to access its properties:

site

site exposes the organized collection of metadata that Trio creates from your project's assets. Its catalogs - frags, articlesCatalog, categoriesCatalog, tagsCatalog, dataCatalog - as well as its other properties can all be used to create a collection dataset.

collection

collection is a reference to the fragment's front matter's collection hash.

Filter functions are called synchronously.

Trio uses import-fresh internally to import uncached collection filter functions.

module.exports = ({ site, collection }) =>
    site.dataCatalog.team.map(item =>
        ({ pageName: `${item.firstName} ${item.lastName}`, data: item }));
Example: Filter Function Returning A Collection Dataset

Importing Uncached Internal Module Dependencies

When your filter functions have their own internal module dependencies, you should import those dependencies using import-fresh (or some similar package) to guarantee that you are always importing fresh, uncached copies of them and they reflect your most recent changes.

const importFresh = require('import-fresh');
const pageName = importFresh("./lib/pageName");
module.exports = ({ site, collection }) =>
    site.dataCatalog.team.map(item =>
        ({ pageName: `${pageName(item.firstName, item.lastName)}`, data: item }));
Example: Filter Function Importing Uncached Module Dependency

Tag-Based Callbacks

The following properties, including those from the collection dataset item, are exposed to tag-based callbacks via the asset.collection property:

asset.collection.pageName

The name of this page that was assigned to the collection dataset item's pageName property.

See dataset item data properties above.

asset.collection.data

The data that was assigned to the collection dataset item's data property.

See dataset item data properties above.

asset.collection.index

The zero-based index of the collection dataset item that contributed its data to this page.

asset.collection.totalItems

The total number of collection dataset items in the collection dataset.

In addition to the above properties, any custom properties that you add to collection dataset items are also accessible.

module.exports = ({ $tag, asset }) => {
    const data = asset.collection.data;
    $tag.find("#name").append(`${data.firstName} ${data.lastName}`);
    $tag.find("#title").append(data.title);
    $tag.find("#bio").append(data.bio);
Example: /source/callbacks/teamMember.js Tag-Based Callback Function

Demo

A demo collections project is available on Github that you can copy, build, run and examine.

See Also