Partial templates
Partial templates provide a powerful way to organize and modularize your UI view and UI component templates. They allow you to break down complex templates into smaller, more manageable pieces while maintaining the full context and scope of the parent (UI view or UI component).
Overview
A partial template is a reusable template fragment that can be defined within a UI view or UI component and referenced from its main template or its other partial templates.
When the application is generated, the <partial-template /> node is replaced by the actual content of the partial template.
Key characteristics:
- Scoped to the UI view or UI component where they are defined
- Cannot be shared between multiple UI views or UI components
- Have access to the same context (properties, actions, methods, computeds, ...) as the main template of the UI view/UI component
- Can reference other partial templates within the same component
- Evaluated at generation time, not runtime
Common use cases
Splitting large templates
Break down complex templates into logical sections for better maintainability:
<partial-template name="CustomerHeader" />
<partial-template name="CustomerContactInfo" />
<partial-template name="CustomerOrderHistory" />
<partial-template name="CustomerActions" />
Responsive templates
Create different layouts based on screen size:
<if condition="@Viewport.IsWidthAtLeastMedium">
<partial-template name="DesktopLayout" />
</if>
<else>
<partial-template name="MobileLayout" />
</else>
Comparison with UI components
| Aspect | Partial Templates | UI Components |
|---|---|---|
| Scope | Limited to the parent UI view/UI component | Reusable across multiple UI views/components |
| Context | Full access to parent UI view/UI component context | The context must explicitly be passed as parameters or accessed via the GetParentViewModel/GetMainViewModel methods |
| Reusability | Cannot be shared | Can be used anywhere |
| Use case | Template organization inside a single UI view/UI component | Components reusable across the whole application to manage common functionalities available in multiple screens |
When to use partial templates
- Breaking down complex templates
- Creating conditional (responsive) layouts inside the same UI view/UI component
- Organizing template code for better readability without introducing new abstraction surface
When to use UI components
- Reusing functionality or layout across multiple UI views/UI components
- Encapsulating complex behavior that needs parameters, its own events, or isolated state
- Sharing a pattern broadly across the cluster (or future clusters) for consistency
Partial template types
A partial template has a type, which defines how it is used:
| Type | Description |
|---|---|
Standard |
Default type. The partial template is referenced by name with the <partial-template /> node. |
SlotContribution |
The partial template is a contribution to a slot. It is inserted by the slot, never by its own name. |
Existing partial templates have no type in their metadata: they are Standard.
Two additional properties are available on a UI view partial template:
| Property | Type | Default value | Description |
|---|---|---|---|
Slot |
string |
Name of the slot, in PascalCase. Required for a SlotContribution, forbidden for a Standard partial. |
|
Order |
integer |
0 |
Display order among the contributions of a slot. Only for a SlotContribution. |
Slots
A slot is a named location that a UI view declares in its template with the <partial-template-slot /> node. Other modules complete the UI view by contributing partial templates to this location, without the module declaring the UI view knowing them.
This allows a base module to define a screen that is complete on its own, and sibling modules depending on the base module to add their own content to it.
Key characteristics:
- Slots are available in UI views only: a
<partial-template-slot />node in a UI component template is a generation error - Native Vue views (
VuejsComponentContent) do not support slots - Inside a
contextnode, a slot belongs to the UI view bound by the context, like a<partial-template />node - A slot without contribution renders nothing
- Each contribution is validated against its own module
- A contribution cannot be referenced by a
<partial-template />node: it is only inserted by its slot
Example
The module Dashboard declares a UI view with a Sections slot inside a tabs node:
<tabs>
<tab-item caption="Overview">
<text>Overview</text>
</tab-item>
<partial-template-slot name="Sections" />
</tabs>
The module Sales, which depends on Dashboard, contributes a tab. The contribution is defined in the metadata of the Sales module (file UIViewPartialTemplates/DashboardUI.yml, named after the UI view):
- Name: SalesSection
Order: 10
Slot: Sections
Template: |-
<tab-item caption="Sales">
<text>Sales</text>
</tab-item>
Type: SlotContribution
The module Stock, which also depends on Dashboard but not on Sales, contributes another tab in the same way:
- Name: StockSection
Order: 20
Slot: Sections
Template: |-
<tab-item caption="Stock">
<text>Stock</text>
</tab-item>
Type: SlotContribution
When Sales and Stock are present, the generated UI view displays the tabs Overview, Sales and Stock. When only Dashboard is present, it displays the Overview tab alone.
The root elements of a contribution are inserted where the slot is declared. An element that requires a given parent, like a tab-item in a tabs, is therefore checked against that place when the application is generated. Neos Studio analyzes a contribution alone, so it never reports a missing parent for the root elements of a contribution.
Sorting of the contributions
The contributions to a slot are sorted, whatever the order in which the modules are loaded:
- By
Order, ascending. - For an equal order, the modules are placed so that a module comes after the modules it depends on. Among the modules whose dependencies are already placed, the smallest module name (ordinal comparison) comes first.
- Then by partial template name (ordinal comparison).
A contribution that overrides another one (with OverridenValues) is sorted under the name of its own module.
Errors
The following cases are reported as errors when the application is generated:
- A contribution targets a slot that no template of the UI view declares.
- Two different
<partial-template-slot />nodes of the same UI view declare the same slot, even in the two branches of anif/else. A standard partial template that declares a slot can still be used several times: the contributions are written at each use. - A slot is declared inside a contribution.
- A slot is declared inside a
repeatnode (the only loop component taken into account). - A slot is declared in a UI component template.
- The
nameof a<partial-template-slot />node is not in PascalCase. - A contribution has no
Slot, or theSlotof a contribution is not in PascalCase, or aStandardpartial template defines aSlotor anOrder. - A contribution is referenced by a
<partial-template />node. - Two partial templates of a UI view have the same name, unless the second one overrides the first one with
OverridenValues.