Appearance
x:for Directive
The x:for directive is used to render lists by looping over arrays.
Basic Usage
Syntax
html
<template x:for="item in array">
<!-- Content to be rendered for each item -->
</template>Usage with Index
typescript
@Widget({
selector: '.indexed-list',
template: `
<template x:for="item, index in items">
<div>
<span x:text="index"></span>: <span x:text="item.name"></span>
</div>
</template>
`
})
export class IndexedListWidget {
@xproperty()
items: Array<{name: string}> = [
{ name: 'Item 1' },
{ name: 'Item 2' },
{ name: 'Item 3' }
];
}Nested Properties
typescript
@Widget({
selector: '.nested-list',
template: `
<template x:for="user in users">
<div class="user-card">
<h3 x:text="user.profile.name"></h3>
<p x:text="user.profile.email"></p>
<span x:text="user.status"></span>
</div>
</template>
`
})
export class NestedListWidget {
@xproperty()
users = [
{
profile: { name: 'Ahmet', email: 'ahmet@example.com' },
status: 'active'
},
{
profile: { name: 'Mehmet', email: 'mehmet@example.com' },
status: 'inactive'
}
];
}Event Binding
typescript
@Widget({
selector: '.event-list',
template: `
<template x:for="item, index in items">
<div class="item">
<span x:text="item.name"></span>
<button x:on:click="editItem(index)">Edit</button>
<button x:on:click="deleteItem(index)">Delete</button>
</div>
</template>
`
})
export class EventListWidget {
@xproperty()
items: Array<{name: string}> = [
{ name: 'Item 1' },
{ name: 'Item 2' }
];
editItem(index: number): void {
console.log('Editing:', this.items[index]);
}
deleteItem(index: number): void {
this.items.splice(index, 1);
}
}Conditional Rendering
typescript
@Widget({
selector: '.conditional-list',
template: `
<template x:for="item in items">
<div x:class:active="item.isActive">
<span x:text="item.name"></span>
<span x:if="item.isNew">NEW</span>
<span x:if="item.discount > 0" x:text="item.discount + '%'"></span>
</div>
</template>
`
})
export class ConditionalListWidget {
@xproperty()
items = [
{ name: 'Product 1', isActive: true, isNew: true, discount: 20 },
{ name: 'Product 2', isActive: false, isNew: false, discount: 0 }
];
}Dynamic List Management
typescript
@Widget({
selector: '.dynamic-list',
template: `
<div>
<input x:model="newItem" placeholder="New item">
<button x:on:click="addItem">Add</button>
<template x:for="item, index in items">
<div class="item">
<span x:text="item"></span>
<button x:on:click="removeItem(index)">Delete</button>
</div>
</template>
<p x:if="items.length === 0">List is empty</p>
</div>
`
})
export class DynamicListWidget {
@xproperty()
items: string[] = [];
@xproperty()
newItem: string = '';
addItem(): void {
if (this.newItem.trim()) {
this.items.push(this.newItem.trim());
this.newItem = '';
}
}
removeItem(index: number): void {
this.items.splice(index, 1);
}
}Nested Loops
typescript
@Widget({
selector: '.nested-loop',
template: `
<template x:for="category in categories">
<div class="category">
<h3 x:text="category.name"></h3>
<template x:for="product in category.products">
<div class="product">
<span x:text="product.name"></span>
<span x:text="product.price"></span>
</div>
</template>
</div>
</template>
`
})
export class NestedLoopWidget {
@xproperty()
categories = [
{
name: 'Electronics',
products: [
{ name: 'Laptop', price: 15000 },
{ name: 'Phone', price: 8000 }
]
},
{
name: 'Clothing',
products: [
{ name: 'T-Shirt', price: 150 },
{ name: 'Pants', price: 300 }
]
}
];
}Computed Arrays
typescript
@Widget({
selector: '.filtered-list',
template: `
<div>
<input x:model="searchQuery" placeholder="Search...">
<template x:for="item in filteredItems">
<div>
<span x:text="item.name"></span>
</div>
</template>
<p x:if="filteredItems.length === 0">No results found</p>
</div>
`
})
export class FilteredListWidget {
@xproperty()
items = [
{ name: 'Apple' },
{ name: 'Pear' },
{ name: 'Banana' }
];
@xproperty()
searchQuery: string = '';
@xcomputed({ dependencies: ['items', 'searchQuery'] })
get filteredItems() {
if (!this.searchQuery) {
return this.items;
}
const query = this.searchQuery.toLowerCase();
return this.items.filter(item =>
item.name.toLowerCase().includes(query)
);
}
}Performance Tips
Large Lists
typescript
@Widget({
selector: '.large-list',
template: `
<template x:for="item in visibleItems">
<div x:text="item.name"></div>
</template>
`
})
export class LargeListWidget {
@xproperty()
allItems: any[] = []; // Thousands of items
@xproperty()
pageSize: number = 20;
@xproperty()
currentPage: number = 1;
@xcomputed({ dependencies: ['allItems', 'currentPage', 'pageSize'] })
get visibleItems() {
const start = (this.currentPage - 1) * this.pageSize;
const end = start + this.pageSize;
return this.allItems.slice(start, end);
}
}Summary
- List rendering: Loop over arrays
- Index support:
item, index in arraysyntax - Nested loops: Nested loops
- Event binding: Event handlers for each item
- Conditional: Conditional rendering with x:if, x:class
- Computed arrays: Filtering and sorting
- Dynamic: List updates with push, splice
- Performance: Optimization with computed properties