UI Template Injection
UI Template Injection
since 8.0.0
In ZK, <template> is the recommended way to reuse a view pattern composed by a group of components. By defining components within a <template>, you can easily reuse them across different parts of your application using the <apply> shadow element.
The process typically involves two steps:
- Define a template: Specify the UI structure.
- Apply a template: Inject the template into the component tree.
+-------------------------+ +-------------------+
| Define Template | -----> | Apply Template |
| (No components created) | | (Creates UI) |
+-------------------------+ +-------------------+
Define a Template
You can define a <template> inside any component. A template remains dormant and does not create any components until it is applied.
Inline Template
Define the UI components directly within the tag:
<div>
<template name="layout">
<label value="This is an inline template"/>
</template>
</div>
External Template
Reference an external ZUL file using the src attribute:
<div>
<template name="layout" src="/mytemplate.zul"/>
</div>
Apply a Template
When you apply a template, ZK creates the components defined inside it and inserts them at the location of the <apply> tag.
By Name
Apply a template defined within the current component scope:
<apply template="layout"/>
By URI
Apply an external ZUL file directly:
<apply templateURI="/chapter1/banner.zul"/>
Passing Parameters
You can pass data to templates to make them dynamic and reusable for different data sets.
Dynamic Properties
Add attributes directly to the <apply> tag. These become available as variables (or within the arg map) inside the template.
<apply template="userProfile" username="John Doe" role="Admin"/>
Reference Binding Passing
In MVVM, use @ref to pass object references efficiently without triggering full data loading until needed in the template.
<apply template="iterate" menuItems="@ref(vm.menuHierarchy)"/>
Query Strings for URI
When using templateURI, you can pass parameters via a query string. Note that parameters passed this way are always Strings.
<apply templateURI="/mytemplate.zul?mode=edit&id=123"/>
You can access these parameters in the applied page using:
- EL:
${arg.mode} - Java:
Executions.getCurrent().getArg().get("mode")
Recursive Templates
Recursive template application is a powerful pattern for rendering hierarchical data like menus or trees.
<template name="menu">
<nav label="@load(menuItem.label)" iconSclass="@load(menuItem.iconSclass)">
<!-- Apply the same 'iterate' template for sub-menus -->
<apply template="iterate" menuItems="@ref(menuItem.subMenus)"/>
</nav>
</template>
<template name="iterate">
<forEach items="@load(menuItems)">
<apply template="@load(empty each.subMenus ? 'menuitem' : 'menu')" menuItem="@ref(each)"/>
</forEach>
</template>
<template name="menuitem">
<navitem label="@load(menuItem.label)" />
</template>
Programmatic Usage: ShadowTemplate
For component developers working in Java, ZK provides the ShadowTemplate class (since 8.0.0) to apply templates programmatically.
ShadowTemplate st = new ShadowTemplate(true); // true for 'autodrop'
st.setTemplate("myTemplate");
st.setDynamicProperty("data", myData);
st.apply(hostComponent);
Autodrop Feature
autodrop = true: Automatically detaches previously rendered children when the template or host changes. This is the behavior most consistent with the<apply>tag.autodrop = false: Rendered children remain even if theShadowTemplateis detached or changed.
Performance Considerations
Using shadow elements (like <apply> or <forEach>) inside templates that are rendered frequently (e.g., inside a listbox model template) can incur a performance cost.
<listbox model="@load(vm.listModel)">
<template name="model">
<!-- Warning: High rendering cost if listModel is large -->
<apply template="rowTemplate" />
</template>
</listbox>
Why? Shadow elements must sync their position in the component tree relative to siblings. In large collections, adding/removing shadow elements causes recalculations for all siblings at the same level.
Recommendation:
If you need dynamic component selection in a large list, use Dynamic Templates or forEach instead of nested <apply> tags.