Facet-sjabloonsyntaxis

Facet-sjabloonsyntaxis

Facet is de sjabloontaal die FaceFlow gebruikt voor dynamische rendering.

Gebruik deze pagina als de primaire syntaxisgids. Het behandelt de patronen die technische gebruikers daadwerkelijk nodig hebben bij het schrijven van Component-sjablonen, Variabele-sjablonen, lijstitem-uitvoer en andere runtimefragmenten binnen FaceFlow.

Deze pagina is opzettelijk gedetailleerd. Het is niet alleen een quick-startgids. Het is het hoofddocument voor officiële FaceFlow-sjabloonschrijvers.

Syntaxisfamilies

Facet-sjablonen combineren meestal vijf syntaxisfamilies:

SyntaxisRolTypisch gebruik
{field}Component-velduitvoerdirecte uitvoer van een Component-veld
{{ expr }}ge-escaped expressie-uitvoerpaginagegevens, contextobjecten, filters
{{{ expr }}}rauwe uitvoervertrouwde rijke inhoud en gecontroleerde markup
{{#block}}...{{/block}}controleflowvoorwaarden, lussen, pagina-queries, deferred-uitvoer
[[variable-name]]herbruikbare fragment-embedgedeelde sjabloonfragmenten met optionele attributen

De meest voorkomende bron van verwarring is het mixen van Component-veldafkorting met algemene Facet-expressies. Houd die grens duidelijk:

  • gebruik {field} wanneer het contract van het eigenaar-Componentveld directe velduitvoer of veldhelpers ondersteunt
  • gebruik {{ ... }} bij het renderen van algemene contextbewuste expressies
  • gebruik [[variable-name]] wanneer de juiste oplossing hergebruik is, niet meer sjabloonlogica

Snelstart

Het minimaal nuttige Facet-mentale model is:

<section class="hero">
  <h1>{{ page.title }}</h1>

  {{#if summary}}
    <p>{{ summary }}</p>
  {{/if}}

  [[sales-contact-badge]]
</section>

Dat enkele voorbeeld toont al de drie belangrijkste bouwstenen:

  • waarde-uitvoer
  • conditionele structuur
  • herbruikbare fragmentcompositie

Uitvoersyntaxis

Componentvelduitvoer

In Component-sjablonen gebruikt directe velduitvoer vaak enkel-accoladesyntaxis:

<h2>{title}</h2>
<p>{summary}</p>

Gebruik dit wanneer het Component-veldcontract eenvoudig en veldgeoriënteerd is.

Voor helper-compatibele velden breidt dezelfde familie zich uit naar helper-syntaxis:

<img src="{heroImage.webp}" alt="{heroImage.description}">
<div data-form-embed="{contactForm}"></div>
<div data-review-embed="{serviceReview}"></div>

Ga er niet van uit dat elk veld helper-chaining ondersteunt. Controleer eerst de referentie van het eigenaarveld.

Ge-escaped expressie-uitvoer

Gebruik dubbele accolades voor normale ge-escaped uitvoer:

<h1>{{ page.title }}</h1>
<p>{{ summary | default("No summary available.") }}</p>

Dit is de standaardkeuze voor platte tekst, labels, URL's, dynamische scalare waarden en alle gevallen waar HTML escaped moet worden.

Rauwe uitvoer

Gebruik drievoudige accolades wanneer de bron vertrouwd is en als HTML moet worden gerenderd:

<div class="prose">
  {{{ body }}}
</div>

Dit is geschikt voor:

  • beheerde rich text
  • gecontroleerde HTML-fragmenten
  • vertrouwde redactionele inhoud

Gebruik geen rauwe uitvoer voor willekeurige onbetrouwbare strings.

Commentaar

Facet ondersteunt korte en lange commentaren:

{{! short comment }}

{{!--
long comment
spanning multiple lines
--}}

Commentaar wordt nooit in de uitvoer weergegeven.

Expressiesyntaxis

Expressies zijn de basis van dynamische sjabloonuitvoer. Ze laten je geneste eigenschappen benaderen, helper-achtige methoden aanroepen, filters toepassen en conditionele inline-logica gebruiken.

Puntpadnotatie

Bereik geneste eigenschappen met puntnotatie:

{{ page.title }}
{{ page.parent.title }}
{{ page.parent.parent.name }}
{{ user.language.title }}

Pijlnotatie wordt ook geaccepteerd op plaatsen waar auteurs op een natuurlijke manier objecttoegang typen:

{{ page->parent->title }}
{{#if page->parent->hasChildren}}
  ...
{{/if}}
{{#each page->children as="child"}}
  ...
{{/each}}

Gebruik welke stijl duidelijker is binnen het huidige sjabloon, maar blijf consistent binnen één bestand.

Method-achtige aanroepen

Sommige objecten bieden method-achtige transformaties of opzoekingen:

{{ page.image.width(800) }}
{{ page.image.size(600, 400) }}
{{ page.image.size(600, 400).webp.url }}

Deze zijn gebruikelijk voor:

  • afbeeldingen
  • collecties
  • paginalokaliseerde URL's
  • pagina-bewuste query-helpers

Method-achtige aanroepen maken deel uit van het Facet-objectmodel, niet van willekeurige runtime-code-uitvoering.

Sleutel-waarde parameters

Sommige helpers accepteren benoemde parameters:

{{ page.field name="summary" }}
{{ page.children selector="limit=5" }}
{{ pages.count selector="template=blog-post" }}

Gebruik benoemde parameters wanneer het helpercontract deze expliciet verwacht. Dit houdt sjablonen leesbaar en voorkomt het overladen van positionele argumenten.

Ternary-expressies

Facet ondersteunt ternary-uitvoerlogica:

{{ user.isLoggedin ? "Welcome back!" : "Please sign in." }}
{{ page.summary ? page.summary : "No summary provided." }}

Gebruik ternaries voor korte uitvoerbeslissingen. Als de vertakking structureel wordt, geef de voorkeur aan een block-helper zoals {{#if}}.

Filterketens

Gebruik de pipe-operator om waarden te transformeren:

{{ page.title | upper }}
{{ page.body | striptags | truncate(200, "...") }}
{{ published | date("F j, Y") }}
{{ price | currency("$", 2) }}

Filters worden van links naar rechts geketend.

Stijlen voor filterargumenten

Facet accepteert zowel haakjesstijl als dubbelpuntstijl argumenten:

{{ page.title | truncate(100, "...") }}
{{ page.title | truncate:100:... }}

Beide vormen worden ondersteund. Geef de voorkeur aan haakjesstijl in officiële sjablonen omdat die duidelijker is en gemakkelijker te reviewen.

Block-helpers

Block-helpers bieden structuur, niet alleen scalare uitvoer.

Facet ondersteunt deze kernbloktypes:

BlokDoel
{{#if}}conditionele weergave
{{#each}}itereren over bestaande arrays of collecties
{{#pages}}een set pagina's opvragen
{{#page}}één pagina opvragen
{{#languages}}beschikbare talen itereren
{{#deferred}}cache-compatibele deferred rendering

{{#if}}

Gebruik {{#if}} voor conditionele rendering:

{{#if summary}}
  <p>{{ summary }}</p>
{{/if}}

Met else:

{{#if user.isLoggedin}}
  <p>Hello, {{ user.name }}.</p>
{{else}}
  <p>Please sign in.</p>
{{/if}}

Met elseif:

{{#if page.template == "blog-post"}}
  <span class="badge">Blog</span>
{{elseif page.template == "case-study"}}
  <span class="badge">Case Study</span>
{{else}}
  <span class="badge">Page</span>
{{/if}}

De else if-variant wordt ook geaccepteerd:

{{#if page.numChildren > 10}}
  <p>Many children</p>
{{else if page.numChildren > 0}}
  <p>Some children</p>
{{else}}
  <p>No children</p>
{{/if}}

Vergelijkingsoperatoren

OperatorBetekenisVoorbeeld
==gelijkpage.template == "blog-post"
!=niet gelijkpage.status != 1
>groter danpage.numChildren > 5
<kleiner danpage.numChildren < 3
>=groter of gelijkpage.sort >= 0
<=kleiner of gelijkpage.sort <= 10

Logische operatoren

OperatorBetekenisVoorbeeld
&&ENuser.isLoggedin && user.isSuperuser
||OFpage.template == "blog-post" || page.template == "news"
!NIET!user.isGuest

Waarheidsregels

Facet-waarheidswaarden volgen een praktisch sjabloongericht model:

WaardeWaar?
nullonwaar
falseonwaar
""onwaar
0onwaar
"0"onwaar
lege array of lege collectieonwaar
alles anderswaar

Als de conditieslogica bedrijfsregels begint te bevatten in plaats van eenvoudige weergaveregels, keer dan terug naar het objectmodel. Verberg geen zwak contentontwerp achter geneste if-blokken.

{{#each}}

Gebruik {{#each}} wanneer de collectie al bestaat in de huidige context:

{{#each page.children as="child"}}
  <a href="{{ child.url }}">{{ child.title }}</a>
{{/each}}

Met shorthand this:

{{#each page.images}}
  <img src="{{ this.url }}" alt="{{ this.description }}">
{{/each}}

Met else:

{{#each page.children as="child"}}
  <div>{{ child.title }}</div>
{{else}}
  <p>No child pages found.</p>
{{/each}}

Luskontekstvariabelen

Binnen lusblokken zijn deze waarden beschikbaar:

VariabeleBeschrijving
loop.indexnul-gebaseerde index
loop.index1één-gebaseerde index
loop.firsttrue bij de eerste iteratie
loop.lasttrue bij de laatste iteratie
loop.lengthtotaal aantal items
loop.eventrue bij even indices
loop.oddtrue bij oneven indices
@indexkorte alias van loop.index

Voorbeeld:

{{#each page.children as="child"}}
  <div class="{{#if loop.odd}}row-alt{{/if}}">
    <span>{{ loop.index1 }}.</span>
    {{ child.title }}
  </div>
{{/each}}

this vs benoemde aliassen

Binnen {{#each}} wijst this altijd naar het huidige item.

{{#each page.children}}
  <a href="{{ this.url }}">{{ this.title }}</a>
{{/each}}

Als leesbaarheid belangrijk is, geef de voorkeur aan een expliciete alias:

{{#each page.children as="child"}}
  <a href="{{ child.url }}">{{ child.title }}</a>
{{/each}}

{{#pages}}

Gebruik {{#pages}} wanneer het sjabloon inhoud moet opvragen in plaats van een collectie te renderen die al in scope aanwezig is.

{{#pages selector="template=blog-post, sort=-created, limit=5" as="post"}}
  <article>
    <h2><a href="{{ post.url }}">{{ post.title }}</a></h2>
    <time>{{ post.created | date("F j, Y") }}</time>
    <p>{{ post.summary | truncate(200) }}</p>
  </article>
{{else}}
  <p>No posts found.</p>
{{/pages}}

Typische parameters:

ParameterBeschrijving
selectorquery-selectorstring
asnaam van de lusvariabele

Gebruik {{#pages}} voor:

  • archieven
  • lijstpagina's
  • widgets met recente inhoud
  • navigatiecollecties
  • query-gestuurde inhoudsblokken

Gebruik {{#each}} wanneer de collectie al bestaat. Gebruik {{#pages}} wanneer het sjabloon deze moet ophalen.

{{#page}}

Gebruik {{#page}} wanneer slechts één pagina moet worden opgevraagd:

{{#page path="/about/"}}
  <a href="{{ page.url }}">{{ page.title }}</a>
{{/page}}

Ondersteunde lookup-patronen omvatten:

{{#page id="1024"}}...{{/page}}
{{#page path="/about/"}}...{{/page}}
{{#page name="contact"}}...{{/page}}
{{#page selector="template=homepage"}}...{{/page}}

Binnen een {{#page}}-blok verwijst page gedurende de duur van dat blok naar de opgevraagde pagina.

{{#languages}}

Gebruik {{#languages}} om taalbewuste UI's te bouwen zoals taalkeuze-elementen:

<nav class="lang-switch">
  {{#languages as="lang"}}
    <a href="{{ lang.url }}" {{#if lang.isCurrent}}class="active"{{/if}}>
      {{ lang.title }}
    </a>
  {{/languages}}
</nav>

Met een lege fallback:

{{#languages as="lang"}}
  <a href="{{ lang.url }}">{{ lang.title }}</a>
{{else}}
  {{! single-language site }}
{{/languages}}

Handige taal-eigenschappen zijn onder andere:

  • lang.id
  • lang.name
  • lang.title
  • lang.isDefault
  • lang.isCurrent
  • lang.url
  • lang.httpUrl
  • lang.locale

{{#deferred}}

Gebruik {{#deferred}} wanneer de pagina cache-zwaar is maar een deel van de inhoud afhankelijk is van per-gebruiker of snel veranderende runtimegegevens.

{{#deferred}}
  <span>Welcome, {{ user.name }}!</span>
{{/deferred}}

Met aangepaste skeleton-afmetingen:

{{#deferred skeleton-width="12rem" skeleton-height="2em"}}
  <div class="user-panel">
    <span>{{ user.displayName }}</span>
  </div>
{{/deferred}}

Gebruik het voor:

  • gebruiker-bewuste begroetingen
  • accountpanelen
  • cache-veilige personalisatie
  • andere inhoud die niet in een volledig pagina-cached HTML-antwoord vastgeplakt moet worden

deferred moet doelbewust gebruikt worden. Wikkel niet standaard alles dynamisch in.

Contextobjecten

Facet maakt een set root-level contextobjecten beschikbaar in elk ondersteund render-oppervlak.

Veelvoorkomende objecten zijn:

  • page
  • pages
  • user
  • languages / lang
  • site
  • now
  • attr
  • loop
  • this

Binnen Component-sjablonen worden Component-veldwaarden ook op rootniveau blootgesteld:

<h1>{{ title }}</h1>

{{#if showGallery}}
  <div class="gallery">
    {{#each images as="img"}}
      <img src="{{ img.url }}">
    {{/each}}
  </div>
{{/if}}

De diepe objectreferentie is gedocumenteerd in:

Afbeeldingsuitvoergrens

Afbeeldingssyntaxis hangt af van waar het afbeeldingobject vandaan komt.

Component image veld helper-syntaxis

<img src="{heroImage.width(1200).webp}" alt="{heroImage.description}">

Pagina- of query-afbeeldingsobject-syntaxis

{{#each page.images as="img"}}
  <img src="{{ img.width(800).webp.url }}" alt="{{ img.description }}">
{{/each}}

Component images veld lus-syntaxis

{{#each gallery}}
  <img src="{{this.width(1200).webp}}" alt="{{this.description}}">
{{/each}}

Meng deze vormen niet lichtvaardig. Het eigenaarveld of runtime-object bepaalt welke syntaxis correct is.

Kaarthelper-uitvoer

Kaartachtige velden kunnen helper-georiënteerde uitvoer blootstellen:

{officeLocation}
{officeLocation.width(600)}
{officeLocation.height(400)}
{officeLocation.size(800,500)}

Gebruik dit alleen wanneer het veldcontract dit expliciet documenteert.

Variabele-embedding

Variabelen worden ingebed met dubbelblokhaak-syntaxis:

[[site-announcement]]
[[cta-badge label="New" tone="accent"]]

Binnen het Variabele-sjabloon zijn doorgegeven waarden beschikbaar via attr.

Variabelen zijn bedoeld voor herbruikbare fragmenten, niet voor het vervangen van degelijk objectontwerp. Als het fragment uitgroeit tot een sectiecontract, keer dan terug naar Component-ontwerp.

Beheerde embed-markers

Formulieren en Reviews worden typisch gerenderd via beheerde embed-markers.

Vast model-embed:

<div data-form-embed="enterprise-demo-request"></div>
<div data-review-embed="customer-success-reviews"></div>

Veld-ondersteunde embed binnen een herbruikbare Component:

<div data-form-embed="{contactForm}"></div>
<div data-review-embed="{serviceReview}"></div>

Beslisregel:

  • vaste embed wanneer het sjabloon één stabiele beheerde workflow bezit
  • veld-ondersteunde embed wanneer auteurs het beheerde model tijdens het aanmaken moeten kunnen kiezen

Gebruiksgids

  • houd sjabloonlogica leesbaar
  • geef de voorkeur aan sterke veldcontracten boven slimme sjabloontrucs
  • gebruik {{#if}} voor structuur, niet om zwak contentontwerp te verbergen
  • gebruik {{#each}} wanneer de collectie al bestaat
  • gebruik {{#pages}} wanneer het sjabloon de collectie moet opvragen
  • gebruik Variabelen voor kleine herbruikbare fragmenten
  • keer terug naar Component- of Lijstontwerp wanneer de sjabloonlogica te complex wordt

Veelvoorkomende fouten

Vermijd deze patronen:

  • rauwe uitvoer gebruiken waar ge-escaped uitvoer veiliger is
  • Component-veldafkorting en generieke Facet-expressies mixen zonder het verschil te begrijpen
  • een content-modelleringsprobleem alleen met conditionals oplossen
  • één gigantisch genest sjabloon bouwen in plaats van objectgrenzen verduidelijken
  • hetzelfde fragment herhalen over sjablonen in plaats van een Variabele te extraheren
  • veld-helper-syntaxis gebruiken op velden die het niet ondersteunen

Snelle beslisgids

need to show one value                 -> {field} or {{ expr }}
need trusted HTML output               -> {{{ expr }}}
need to show content conditionally     -> {{#if}}
need to loop existing items            -> {{#each}}
need to query content                  -> {{#pages}} or {{#page}}
need language-aware navigation         -> {{#languages}}
need cache-safe dynamic personalization -> {{#deferred}}
need one reusable fragment             -> [[variable-name]]
need a field-specific helper output    -> {field.helper}
need a full reusable section contract  -> return to Component design

Verder