Auto Create Entities
For web apps where most entities are singletons (like headers, modals, sidebars), you can avoid boilerplate with autoCreateEntities.
Without Auto Create
Normally you define both types and entities:
javascript
const types = {
header: {
render(entity, api) {
return html`<header>...</header>`
},
},
sidebar: {
render(entity, api) {
return html`<aside>...</aside>`
},
},
content: {
render(entity, api) {
return html`<main>...</main>`
},
},
}
// Must define every entity
const entities = {
header: { type: "header", title: "My App" },
sidebar: { type: "sidebar", items: [] },
content: { type: "content", text: "" },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
With Auto Create
Let the store create entities automatically:
javascript
const types = {
header: {
render(entity, api) {
return html`<header>...</header>`
},
},
sidebar: {
render(entity, api) {
return html`<aside>...</aside>`
},
},
content: {
render(entity, api) {
return html`<main>...</main>`
},
},
}
// Entities created automatically with same id as type name
const store = createStore({
types,
// no entities object!
autoCreateEntities: true,
})
// store now has:
// store.entities.header (auto-created)
// store.entities.sidebar (auto-created)
// store.entities.content (auto-created)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Initializing Entity State
Use the create() lifecycle event:
javascript
const header = {
create(entity) {
// Runs when entity is first created
entity.title = "My App"
entity.isSticky = true
},
render(entity, api) {
return html`<header class=${entity.isSticky ? "sticky" : ""}>
<h1>${entity.title}</h1>
</header>`
},
}
const sidebar = {
create(entity) {
entity.items = []
entity.isOpen = false
},
render(entity, api) {
return html`
<aside class=${entity.isOpen ? "open" : ""}>
<ul>
${entity.items.map((item) => html`<li>${item}</li>`)}
</ul>
</aside>
`
},
}
// Auto create entities with initialized state
const store = createStore({
types: { header, sidebar },
autoCreateEntities: true,
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
When to Use
✅ Use autoCreateEntities when:
- Most entities are singletons (one per type)
- Types and entity IDs are the same
- You want minimal boilerplate
- Building component-like entities
❌ Don't use when:
- You have multiple entities of the same type
- Entity IDs differ from type names
- You need complex initialization
- You're managing a collection of items
Mixed Approach
You can mix auto-create with manual entities:
javascript
const store = createStore({
types: { header, sidebar, todoItem },
entities: {
// Manually created entities (multiple todos)
todo1: { type: "todoItem", id: "todo1", title: "Buy milk" },
todo2: { type: "todoItem", id: "todo2", title: "Walk dog" },
// header and sidebar will be auto-created
},
autoCreateEntities: true,
})
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Example: TODO App
javascript
import { createStore, mount, html } from "@inglorious/web"
const types = {
app: {
render(entity, api) {
return html`
<div class="app">
${api.render("header")} ${api.render("todoForm")}
${api.render("todoList")}
</div>
`
},
},
header: {
create(entity) {
entity.title = "My Todos"
},
render(entity, api) {
return html`<h1>${entity.title}</h1>`
},
},
todoForm: {
create(entity) {
entity.inputValue = ""
},
addTodo(entity, title, api) {
if (title.trim()) {
const todos = api.getEntity("todoList")
const id = Date.now()
todos.todos[id] = { id, title, completed: false }
entity.inputValue = ""
}
},
render(entity, api) {
return html`
<div class="form">
<input
type="text"
placeholder="Add a todo..."
value="${entity.inputValue}"
@input=${(e) => {
entity.inputValue = e.target.value
}}
/>
<button
@click=${() => api.notify("#todoForm:addTodo", entity.inputValue)}
>
Add
</button>
</div>
`
},
},
todoList: {
create(entity) {
entity.todos = {}
},
deleteTodo(entity, id) {
delete entity.todos[id]
},
render(entity, api) {
const items = Object.values(entity.todos)
return html`
<ul>
${items.map(
(todo) => html`
<li>
${todo.title}
<button
@click=${() => api.notify("#todoList:deleteTodo", todo.id)}
>
Delete
</button>
</li>
`,
)}
</ul>
`
},
},
}
const store = createStore({
types,
autoCreateEntities: true, // Auto-create all entities
})
mount(store, (api) => api.render("app"), document.getElementById("root"))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
With autoCreateEntities, you don't need to define an entities object at all!
Benefits
- Less boilerplate — No duplicate entity definitions
- Clearer intent — Entity ID matches type name
- Initialization pattern — Use
create()for state setup - Scalability — Works well for component-like entities
Next Steps
- Type Composition — Combine with composition patterns
- Quick Start — See it in action
Happy creating! 🚀
Inglorious Web