Todo List
A todo list example demonstrating list state management, input binding, and iteration with the each loop.
Source Code
json
{
"version": "1.0",
"state": {
"todos": {
"type": "list",
"initial": []
},
"newTodo": {
"type": "string",
"initial": ""
}
},
"actions": [
{
"name": "setNewTodo",
"steps": [
{
"do": "set",
"target": "newTodo",
"value": {
"expr": "var",
"name": "value"
}
}
]
},
{
"name": "addTodo",
"steps": [
{
"do": "update",
"target": "todos",
"operation": "push",
"value": {
"expr": "state",
"name": "newTodo"
}
},
{
"do": "set",
"target": "newTodo",
"value": {
"expr": "lit",
"value": ""
}
}
]
},
{
"name": "removeTodo",
"steps": [
{
"do": "update",
"target": "todos",
"operation": "remove",
"value": {
"expr": "var",
"name": "item"
}
}
]
}
],
"view": {
"kind": "element",
"tag": "div",
"props": {
"style": {
"expr": "lit",
"value": "font-family: system-ui, sans-serif; padding: 16px;"
}
},
"children": [
{
"kind": "element",
"tag": "h1",
"props": {
"style": {
"expr": "lit",
"value": "margin: 0 0 8px 0; font-size: 24px;"
}
},
"children": [
{
"kind": "text",
"value": {
"expr": "lit",
"value": "Todo List"
}
}
]
},
{
"kind": "element",
"tag": "p",
"props": {
"style": {
"expr": "lit",
"value": "color: #666; margin: 0 0 16px 0;"
}
},
"children": [
{
"kind": "text",
"value": {
"expr": "lit",
"value": "Add items and manage your todo list."
}
}
]
},
{
"kind": "element",
"tag": "div",
"props": {
"style": {
"expr": "lit",
"value": "display: flex; gap: 8px; margin-bottom: 16px;"
}
},
"children": [
{
"kind": "element",
"tag": "input",
"props": {
"type": {
"expr": "lit",
"value": "text"
},
"style": {
"expr": "lit",
"value": "flex: 1; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; color: #333; background: white;"
},
"value": {
"expr": "state",
"name": "newTodo"
},
"onInput": {
"event": "input",
"action": "setNewTodo",
"payload": {
"expr": "var",
"name": "value"
}
}
}
},
{
"kind": "element",
"tag": "button",
"props": {
"style": {
"expr": "cond",
"if": {
"expr": "bin",
"op": "==",
"left": {
"expr": "state",
"name": "newTodo"
},
"right": {
"expr": "lit",
"value": ""
}
},
"then": {
"expr": "lit",
"value": "padding: 8px 16px; background: #ccc; color: #666; border: none; border-radius: 4px; cursor: not-allowed; font-size: 14px;"
},
"else": {
"expr": "lit",
"value": "padding: 8px 16px; background: #0070f3; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;"
}
},
"disabled": {
"expr": "bin",
"op": "==",
"left": {
"expr": "state",
"name": "newTodo"
},
"right": {
"expr": "lit",
"value": ""
}
},
"onClick": {
"event": "click",
"action": "addTodo"
}
},
"children": [
{
"kind": "text",
"value": {
"expr": "lit",
"value": "Add"
}
}
]
}
]
},
{
"kind": "element",
"tag": "ul",
"props": {
"style": {
"expr": "lit",
"value": "list-style: none; padding: 0; margin: 0;"
}
},
"children": [
{
"kind": "each",
"items": {
"expr": "state",
"name": "todos"
},
"as": "item",
"body": {
"kind": "element",
"tag": "li",
"props": {
"style": {
"expr": "lit",
"value": "display: flex; align-items: center; justify-content: space-between; padding: 12px; margin-bottom: 8px; background: #f5f5f5; border-radius: 4px;"
}
},
"children": [
{
"kind": "element",
"tag": "span",
"props": {
"style": {
"expr": "lit",
"value": "color: #333;"
}
},
"children": [
{
"kind": "text",
"value": {
"expr": "var",
"name": "item"
}
}
]
},
{
"kind": "element",
"tag": "button",
"props": {
"style": {
"expr": "lit",
"value": "padding: 4px 12px; background: #dc2626; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 12px;"
},
"onClick": {
"event": "click",
"action": "removeTodo",
"payload": {
"expr": "var",
"name": "item"
}
}
},
"children": [
{
"kind": "text",
"value": {
"expr": "lit",
"value": "Delete"
}
}
]
}
]
}
}
]
}
]
}
}Features Used
- List state
- String state
- Input binding with onInput
- Each loop for iteration
- List operations (push, remove)
- Action payload passing
How to Run
npm install @constela/core @constela/runtimenpx constela run todo-list.json