Templated Pages
Templated pages allow you to use a single markdown file as a template for many pages with different data. For example:
customers/[customer].md
-> One page per customercountries/[country]/index.md
-> One page per countryweekly-reports/week-[week_num].md
-> One page per time periodcategories/[category]/[product].md
-> One page per product nested in its category
In example 1 above, www.example.com/customers/acme would display information for Acme, while www.example.com/customers/contoso would display information for Contoso.
Declaring a templated page
A templated page is created by adding square brackets round a file name [parameter_name].md
or folder name [parameter_name]
.
The following are equivalent:
pages/customers/[customer].md
pages/customers/[customer]/index.md
The file name in the square brackets becomes a parameter you can reference in the page, with the parameter value as text that replaces the parameter name in the URL. In the above example, you could create a file that looks like this.
pages/
`-- customers/
`-- [customer].md
The contents of [customer].md
would be displayed if you navigate to www.yoursite.com/customers/acme or www.yoursite.com/customers/contoso.
Using page parameters
The parameter passed in the URL can be used to filter for a value in a query result (e.g. a specific customer). This parameter can then be referenced in the page, for example to filter queries and present only data relevant to the parameter value.
A parameter on the page [customer].md
is accessed through the variable:
{$page.params.customer}
You can apply a filter to a query result by appending this code to the query name. This is a standard JavaScript method for filtering data.
.filter(d => d.customer_name === $page.params.customer)
This means that the code will look in the query result d
and include only those rows where the customer_name
is equal to the page's parameter variable.
Adding this to a <Value/>
component:
<Value
data={customers.filter(d => d.customer_name === $page.params.customer)}
column=sales_usd
/>
If filtering lots of components, you can create a new object containing the filtered data and use that instead.
<script>
let filtered_customers = customers.filter(d => d.customer_name === $page.params.customer)
</script>
<Value
data={filtered_customers}
column=sales_usd
/>
Populating templated pages
So far, we've created the template for a set of pages, but haven't specified what specific pages to create, or to put it another way, what values we want the parameter to take.
For a page to exist, there must be links to it somewhere in your project.
Whilst you could add markdown style links for each parameter value, it is easier to programmatically generate them. Two easy options are:
1. With a <DataTable/>
and the link
prop
Create a link per row in the SQL query and pass it to the <DataTable/>
.
```customers
select
customer_name,
'customers/' || customer_name as customer_link,
sum(sales) as sales_usd
from orders
group by 1
```
<DataTable
data={customers}
link=customer_link
/>
2. With an {#each}
loop
```customers
select
customer_name,
sum(sales) as sales_usd
from orders
group by 1
```
{#each customers as customer}
- [{customer.customer_name}](/customers/{customer.customer_name})
{/each}
Nesting templated pages
Creating folders with parameters can be useful when nesting inside templated pages:
pages/
`-- customers/
`-- [customer]/
|-- index.md
`-- [branch].md
Now index.md
would be rendered if you navigate to www.example.com/customers/acme, and [branch].md
would be rendered if you navigate to www.example.com/customers/acme/south.