Advanced Datasource Options¶
Ekit allows advanced configuration of datasources directly in the YAML frontmatter. This enables dynamic sorting, filtering, and pagination without writing backend code.
Example¶
---
layout: default
datasources:
acteurs:
from: "acteurs"
sort:
field: "{{ternary (eq query.type 'acteurs') 'nom' 'titre'}}"
dir: "{{ternary (eq query.s 'desc') 'desc' 'asc'}}"
filter:
field: "{{ternary (eq query.type 'acteurs') 'nom' 'titre'}}"
op: "contains"
value: "{{query.q}}"
limit: 9
---
sort¶
Defines how results are ordered.
Parameters¶
- field: field used for sorting
- dir:
ascordesc
Dynamic example¶
sort:
field: "{{ternary (eq query.type 'acteurs') 'nom' 'titre'}}"
dir: "{{ternary (eq query.s 'desc') 'desc' 'asc'}}"
filter¶
Filters results before rendering.
Parameters¶
- field: field to filter
- op: operator — only
containsis supported (it is also the default) - value: value searched in the field (case-insensitive text match). An empty value disables the filter.
Example¶
filter:
field: "{{ternary (eq query.type 'acteurs') 'nom' 'titre'}}"
op: "contains"
value: "{{query.q}}"
Operators
The rendering engine currently applies contains only. Other operators (eq, gt, in…) are ignored, and the editor flags them.
Pagination¶
List datasources are paginated with a cursor, read from the URL: ?cursor=… for the next page, ?cursor=…&back=true for the previous one. The engine provides, for each list datasource:
cursors.<alias>— cursor of the next pageprevCursors.<alias>— cursor of the previous pagehasMore.<alias>—truewhen a next page existshasPrev.<alias>—truewhen a previous page exists (falseon the first page, also when you come back to it with Previous)
<ul>
{{#each ekdata.articles}}<li>{{this.title}}</li>{{/each}}
</ul>
{{#if hasPrev.articles}}
<a href="/{{lang}}/articles/?cursor={{jsonUrl prevCursors.articles}}&back=true">Previous</a>
{{/if}}
{{#if hasMore.articles}}
<a href="/{{lang}}/articles/?cursor={{jsonUrl cursors.articles}}">Next</a>
{{/if}}
Write the path of the page before ?cursor= (/{{lang}}/articles/, or /{{lang}}/ on the home page): with the <base> tag of the layout, a link starting with ?cursor= alone would open another page.
limitsets the page size (25 withoutlimit); the order followssort(entries with the same value keep a stable order, none is skipped or repeated between pages).- Use
hasPrevrather thanquery.cursorto show Previous: after going back to the first page, the address still contains a cursor. - The
cursorparameter of the URL applies to every list datasource of the page: paginate one list per page. - The
cursorandpagekeys of a datasource are not used by the engine — pagination only relies on the URL.
Number of results and pages (count)¶
Add count: true to a list datasource to show how many entries it has and how many pages:
total.<alias>— number of entries, filter included (all pages together)pages.<alias>— number of pages, according tolimitpage.<alias>— number of the page displayed (1on the first page); available even withoutcount
---
datasources:
articles:
from: articles
limit: 10
count: true
filter:
field: title
op: contains
value: '{{query.q}}'
---
{{#if total.articles}}<p>{{total.articles}} articles</p>{{/if}}
{{#if hasPrev.articles}}
<a href="/{{lang}}/articles/?cursor={{jsonUrl prevCursors.articles}}&back=true">Previous</a>
{{/if}}
{{#if (gt pages.articles 1)}}<span>Page {{page.articles}} / {{pages.articles}}</span>{{/if}}
{{#if hasMore.articles}}
<a href="/{{lang}}/articles/?cursor={{jsonUrl cursors.articles}}">Next</a>
{{/if}}
- The page number travels with the cursor: keep the Previous / Next links as above, there is nothing to compute in the template.
- Enable
countonly on pages that show these numbers: counting costs a little more than reading a page. - On a very large table with a filter, counting may take too long:
totalandpagesare then empty (null). Always show them inside{{#if}}. - An old link (shared before
countwas added) still works; onlypage.<alias>is empty on it.
limit¶
Limits number of returned records.
Often used with cursor. Without limit, a page has 25 entries. The maximum is 200; higher values are capped.
expose — use the data in JavaScript¶
By default, a datasource is only available to the template. Add expose: true to make its resolved value available to the page's JavaScript as ekit.data.<alias>:
- The data is resolved during server rendering: no extra request.
- Only exposed datasources are sent to the browser. Every field of the returned entries is included, so do not expose tables containing data you do not want to publish.
- A single entry (
uid/slug) is an object ornull; a Method datasource is the response body ornull. - Exposed data is limited to 1 MB per page.
when¶
Loads the datasource only when the value is not empty, false, 0 or null. Otherwise ekdata.<alias> is empty ([], or null for a single record or a Method).
datasources:
results:
from: articles
when: '{{query.q}}' # only when a search is submitted
filter:
field: title
value: '{{query.q}}'
Datasources declared in partials¶
A partial can declare its own datasources in its front matter. On a page, Ekit runs:
- the datasources of the view;
- the datasources of every partial the page uses: included by the view or by its layout, including partials included by other partials (
{{> header}}→{{> menu}}).
The datasources of partials that the page does not include are not run: no query, no Method call. There are three exceptions, so that nothing breaks:
| Partial not included, but… | Its datasource runs |
|---|---|
the page uses the alias (ekdata.<alias>, lookup ekdata "<alias>", hasMore.<alias>…) |
Yes |
the datasource has expose: true (read by your JavaScript) |
Yes |
the page uses record and loads no entry itself |
Its single-entry datasources (uid / slug) run |
When Ekit cannot know in advance what a page uses, it runs all the datasources of all partials. This happens with a partial whose name is computed ({{> (name)}}), with the whole ekdata object ({{#each ekdata}}, {{json ekdata}}, lookup ekdata variable), or with the whole page context passed to a helper ({{json this}} outside a loop).
Same alias in several files¶
On a page, each alias runs one datasource. When several files used by the same page declare the same alias:
- a partial's datasource replaces the view's;
- between partials, the one whose file name comes last wins (character order of the full file name:
blog-item.hbscomes beforeblog.hbs, uppercase before lowercase).
The editor flags these collisions: give each datasource its own alias. Two views can use the same alias without any problem, since they are never on the same page.
Request-driven behavior¶
All datasource options support dynamic expressions.
Example:
Will:
- filter records where nom contains "marie"
- sort descending
- adapt field dynamically
Why use advanced datasources¶
- No backend code needed
- Fully dynamic pages
- Works with query parameters
- Supports large datasets efficiently
Related¶
- Template syntax
- Query parameters
- Datasources basics