afv-library/skills/platform-widget-generate/references/widget-meta-directives.md

131 lines
4.6 KiB
Markdown

# Widget Meta Directives Reference
The `meta` object on a UEM block carries runtime directives for iteration (`forEach` / `forItem`) and conditional rendering (`if`). Read this file when a widget needs either.
---
## Iteration with forEach / forItem
`forEach` iterates over an array; the block and ALL its children repeat for each item.
### Rules
- Place `forEach` on the `meta` object of the REPEATING block (e.g. a row or card).
- The value is an expression referencing an array: `{!$attrs.<arrayAttr>}` (or `{!$<outerForItem>.<arrayField>}` for nested loops).
- `forItem` is required alongside `forEach`. It names the variable bound to the current item and must start with `$`.
- Inside the `forEach` block, reach the **current item** through the loop variable (`{!$item.X}`) — not by traversing the array path (`{!$attrs.items.X}`, which does not unfold to the current iteration). Top-level references for values that don't change across iterations (`{!$attrs.<unrelatedField>}`) are still valid.
- `forEach` blocks can be nested — inner loops use their own `forItem` name.
### Example — top-level list
```json
{
"definition": "namespace/repeatingBlock",
"meta": { "forEach": "{!$attrs.items}", "forItem": "$item" },
"children": [
{ "definition": "namespace/childBlock1", "attributes": { "content": "{!$item.id}" } },
{ "definition": "namespace/childBlock2", "attributes": { "content": "{!$item.total}" } }
]
}
```
### Example — container holds repeating child
When a container holds repeating items, `forEach` goes on the child — not on the container.
```json
{
"definition": "namespace/block",
"children": [
{
"definition": "namespace/repeatingBlock",
"meta": { "forEach": "{!$attrs.items}", "forItem": "$item" },
"children": [
{ "definition": "namespace/childBlock", "attributes": { "content": "{!$item.name}" } }
]
}
]
}
```
### Example — nested loops
The inner `forEach` references an array on the outer loop variable and uses a distinct `forItem` name.
```json
{
"definition": "namespace/repeatingBlock",
"meta": { "forEach": "{!$attrs.orders}", "forItem": "$order" },
"children": [
{ "definition": "namespace/childBlock", "attributes": { "content": "{!$order.id}" } },
{
"definition": "namespace/repeatingChildBlock",
"meta": { "forEach": "{!$order.lineItems}", "forItem": "$line" },
"children": [
{ "definition": "namespace/childBlock1", "attributes": { "content": "{!$line.name}" } },
{ "definition": "namespace/childBlock2", "attributes": { "content": "{!$line.count}" } }
]
}
]
}
```
---
## Conditional rendering with if
`if` conditionally renders a block. When the expression is `false`, the block and all its children are excluded from the rendered output.
### Rules
- Place `if` on the `meta` object of the block.
- Use `if` only when the schema has a `lightning__booleanType` property suited to the condition. Bind directly to that property (or to a loop variable holding such a value). If no suitable boolean exists in the schema, do not use `if` — render the block unconditionally instead.
- Do not lean on the truthiness of strings (`""` vs `"value"`), numbers (`0` vs `1`), or nullable fields — that may render today but is not guaranteed across surfaces. Comparisons, arithmetic, and string operations are not supported.
- `if` may coexist with `forEach` on the same `meta`. `if` is evaluated first — if `false`, the loop is skipped entirely.
### Example — top-level boolean
```json
{
"definition": "namespace/block",
"meta": { "if": "{!$attrs.isVerified}" },
"attributes": { "label": "Verified user" }
}
```
### Example — boolean nested inside a schema object
```json
{
"definition": "namespace/block",
"meta": { "if": "{!$attrs.features.showBanner}" },
"attributes": { "text": "Promo banner" }
}
```
### Example — boolean inside a forEach loop
```json
{
"definition": "namespace/repeatingBlock",
"meta": { "forEach": "{!$attrs.tasks}", "forItem": "$task" },
"children": [
{ "definition": "namespace/block1", "attributes": { "content": "{!$task.title}" } },
{
"definition": "namespace/block2",
"meta": { "if": "{!$task.completed}" },
"attributes": { "label": "Done" }
}
]
}
```
---
## Gotchas
| Issue | Resolution |
|---|---|
| `if` bound to a non-boolean (string or number) does not behave as expected | Use `if` only when the schema has a `lightning__booleanType` property; otherwise render the block unconditionally |
| Nested loops share the same `forItem` name | Pick distinct names (e.g. `$item` outer, `$line` inner) — there is no validation error on collision |