@ea-lab/reactive-json-docs 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/public/rjbuild/docs/core/element/form/CheckBoxField.md +364 -0
- package/public/rjbuild/docs/core/element/form/CheckBoxField.yaml +222 -0
- package/public/rjbuild/docs/core/element/form/SelectField.md +384 -0
- package/public/rjbuild/docs/core/element/form/SelectField.yaml +252 -0
- package/public/rjbuild/docs/core/element/form/TextAreaField.md +297 -0
- package/public/rjbuild/docs/core/element/form/TextAreaField.yaml +139 -0
- package/public/rjbuild/docs/core/example/bulk-actions.md +405 -0
- package/public/rjbuild/docs/core/example/bulk-actions.yaml +514 -0
- package/public/rjbuild/docs/core/example/editable-modal-in-row.md +281 -0
- package/public/rjbuild/docs/core/example/editable-modal-in-row.yaml +415 -0
- package/public/rjbuild/docs/getting-started/rjbuild-structure.md +24 -0
- package/public/rjbuild/docs/getting-started/rjbuild-structure.yaml +26 -0
- /package/public/rjbuild/docs/{integration/bootstrap → core}/element/form/formElementsCommon.md +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Editable Modal in Row Template
|
|
2
|
+
|
|
3
|
+
This guide demonstrates a pattern for creating editable modals within row templates, allowing users to edit individual items in a list without complex state management or custom handlers.
|
|
4
|
+
|
|
5
|
+
## Core Concept
|
|
6
|
+
|
|
7
|
+
By placing a modal inside a row template (using `Switch`), each row gets its own modal instance with direct access to the row's data via the `~.` notation. This simplifies data flow and eliminates the need for complex index tracking or custom save handlers.
|
|
8
|
+
|
|
9
|
+
## Key Benefits
|
|
10
|
+
|
|
11
|
+
1. **Simplified data access**: Modal has direct access to row data via `~.` notation
|
|
12
|
+
2. **No index tracking**: No need to find array indices or store file IDs
|
|
13
|
+
3. **Automatic isolation**: Each row's modal is isolated from others
|
|
14
|
+
4. **Simple save pattern**: Use basic `setData` reactions to copy editable values back to originals
|
|
15
|
+
|
|
16
|
+
## Prerequisites
|
|
17
|
+
|
|
18
|
+
Before implementing this pattern, you need:
|
|
19
|
+
|
|
20
|
+
1. **A Reactive-JSON Modal component**: This pattern requires a Modal component implementation that supports:
|
|
21
|
+
- `showBoolPath` property (or equivalent) to control visibility via data path
|
|
22
|
+
- `headerTitle` property for the modal header
|
|
23
|
+
- `body` property for the modal content
|
|
24
|
+
- Integration with Reactive-JSON's action system
|
|
25
|
+
|
|
26
|
+
You can use a custom Modal component or one from an integration package (like `@ea-lab/reactive-json-bootstrap`), but it must be compatible with Reactive-JSON's component system.
|
|
27
|
+
|
|
28
|
+
## Pattern Structure
|
|
29
|
+
|
|
30
|
+
### 1. Modal Inside Row Template
|
|
31
|
+
|
|
32
|
+
Place the modal component inside your row template so each rendered row has its own modal instance:
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
templates:
|
|
36
|
+
itemRow:
|
|
37
|
+
- type: tr
|
|
38
|
+
content:
|
|
39
|
+
# Row content (cells, buttons, etc.)
|
|
40
|
+
- type: button
|
|
41
|
+
content: "Edit"
|
|
42
|
+
actions:
|
|
43
|
+
- what: setData
|
|
44
|
+
on: click
|
|
45
|
+
path: ~.showModal
|
|
46
|
+
value: true
|
|
47
|
+
|
|
48
|
+
# Modal inside the row
|
|
49
|
+
- type: ReactiveJsonSubroot
|
|
50
|
+
sharedUpdates: true
|
|
51
|
+
rjOptions:
|
|
52
|
+
rjBuildUrl: "/components/EditModal.yaml"
|
|
53
|
+
dataOverride:
|
|
54
|
+
showModal: ~.showModal
|
|
55
|
+
# ... other data
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. Separate Editable Values
|
|
59
|
+
|
|
60
|
+
Use separate fields for editable copies and original values:
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
dataOverride:
|
|
64
|
+
# Original values (read-only display)
|
|
65
|
+
id: ~.id
|
|
66
|
+
name: ~.name
|
|
67
|
+
|
|
68
|
+
# Editable copies (for form fields)
|
|
69
|
+
editable_name: ~.editable.name
|
|
70
|
+
editable_description: ~.editable.description
|
|
71
|
+
|
|
72
|
+
# Original values (for saving back)
|
|
73
|
+
name: ~.name
|
|
74
|
+
description: ~.description
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 3. Initialize Editable Values
|
|
78
|
+
|
|
79
|
+
When opening the modal, copy original values to editable fields:
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
- type: button
|
|
83
|
+
content: "Edit"
|
|
84
|
+
actions:
|
|
85
|
+
- what: setData
|
|
86
|
+
on: click
|
|
87
|
+
path: ~.editable.name
|
|
88
|
+
value: ~.name
|
|
89
|
+
- what: setData
|
|
90
|
+
on: click
|
|
91
|
+
path: ~.editable.description
|
|
92
|
+
value: ~.description
|
|
93
|
+
- what: setData
|
|
94
|
+
on: click
|
|
95
|
+
path: ~.showModal
|
|
96
|
+
value: true
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 4. Save Pattern
|
|
100
|
+
|
|
101
|
+
Use simple `setData` reactions to copy editable values back to originals:
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
- type: button
|
|
105
|
+
content: "Save"
|
|
106
|
+
actions:
|
|
107
|
+
- what: setData
|
|
108
|
+
on: click
|
|
109
|
+
path: ~.name
|
|
110
|
+
value: ~.editable_name
|
|
111
|
+
- what: setData
|
|
112
|
+
on: click
|
|
113
|
+
path: ~.description
|
|
114
|
+
value: ~.editable_description
|
|
115
|
+
- what: setData
|
|
116
|
+
on: click
|
|
117
|
+
path: ~.showModal
|
|
118
|
+
value: false
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Complete Example
|
|
122
|
+
|
|
123
|
+
### Parent Component (Table with Rows)
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
renderView:
|
|
127
|
+
- type: table
|
|
128
|
+
content:
|
|
129
|
+
- type: tbody
|
|
130
|
+
content:
|
|
131
|
+
- type: Switch
|
|
132
|
+
content: ~~.items
|
|
133
|
+
singleOption:
|
|
134
|
+
load: itemRow
|
|
135
|
+
|
|
136
|
+
templates:
|
|
137
|
+
itemRow:
|
|
138
|
+
- type: tr
|
|
139
|
+
content:
|
|
140
|
+
- type: td
|
|
141
|
+
content: ~.name
|
|
142
|
+
- type: td
|
|
143
|
+
content:
|
|
144
|
+
- type: button
|
|
145
|
+
content: "Edit"
|
|
146
|
+
actions:
|
|
147
|
+
- what: setData
|
|
148
|
+
on: click
|
|
149
|
+
path: ~.editable.name
|
|
150
|
+
value: ~.name
|
|
151
|
+
- what: setData
|
|
152
|
+
on: click
|
|
153
|
+
path: ~.editable.description
|
|
154
|
+
value: ~.description
|
|
155
|
+
- what: setData
|
|
156
|
+
on: click
|
|
157
|
+
path: ~.showModal
|
|
158
|
+
value: true
|
|
159
|
+
|
|
160
|
+
# Modal inside the row
|
|
161
|
+
- type: ReactiveJsonSubroot
|
|
162
|
+
sharedUpdates: true
|
|
163
|
+
rjOptions:
|
|
164
|
+
rjBuildUrl: "/components/EditModal.yaml"
|
|
165
|
+
dataOverride:
|
|
166
|
+
showModal: ~.showModal
|
|
167
|
+
id: ~.id
|
|
168
|
+
name: ~.name
|
|
169
|
+
editable_name: ~.editable.name
|
|
170
|
+
editable_description: ~.editable.description
|
|
171
|
+
name: ~.name
|
|
172
|
+
description: ~.description
|
|
173
|
+
|
|
174
|
+
data:
|
|
175
|
+
items:
|
|
176
|
+
- id: 1
|
|
177
|
+
name: "Item 1"
|
|
178
|
+
description: "Description 1"
|
|
179
|
+
showModal: false
|
|
180
|
+
editable:
|
|
181
|
+
name: ""
|
|
182
|
+
description: ""
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Modal Component (`/components/EditModal.yaml`)
|
|
186
|
+
|
|
187
|
+
```yaml
|
|
188
|
+
renderView:
|
|
189
|
+
- type: Modal
|
|
190
|
+
showBoolPath: ~.showModal
|
|
191
|
+
headerTitle: "Edit Item"
|
|
192
|
+
body:
|
|
193
|
+
- type: TextField
|
|
194
|
+
label: "Name:"
|
|
195
|
+
dataLocation: ~.editable_name
|
|
196
|
+
- type: TextAreaField
|
|
197
|
+
label: "Description:"
|
|
198
|
+
dataLocation: ~.editable_description
|
|
199
|
+
rows: 3
|
|
200
|
+
footer:
|
|
201
|
+
- type: button
|
|
202
|
+
content: "Cancel"
|
|
203
|
+
actions:
|
|
204
|
+
- what: setData
|
|
205
|
+
on: click
|
|
206
|
+
path: ~.showModal
|
|
207
|
+
value: false
|
|
208
|
+
- type: button
|
|
209
|
+
content: "Save"
|
|
210
|
+
actions:
|
|
211
|
+
- what: setData
|
|
212
|
+
on: click
|
|
213
|
+
path: ~.name
|
|
214
|
+
value: ~.editable_name
|
|
215
|
+
- what: setData
|
|
216
|
+
on: click
|
|
217
|
+
path: ~.description
|
|
218
|
+
value: ~.editable_description
|
|
219
|
+
- what: setData
|
|
220
|
+
on: click
|
|
221
|
+
path: ~.showModal
|
|
222
|
+
value: false
|
|
223
|
+
|
|
224
|
+
data:
|
|
225
|
+
showModal: false
|
|
226
|
+
id: ""
|
|
227
|
+
name: ""
|
|
228
|
+
editable_name: ""
|
|
229
|
+
editable_description: ""
|
|
230
|
+
description: ""
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## How It Works
|
|
234
|
+
|
|
235
|
+
1. **Row Context**: Each row rendered by `Switch` has its own template context, accessible via `~.`
|
|
236
|
+
2. **Modal Access**: The modal inside the row inherits this context, so `~.name` refers to the current row's name
|
|
237
|
+
3. **Editable Copies**: Form fields bind to `~.editable_name` (or `~.editable.name`), keeping edits separate from originals
|
|
238
|
+
4. **Save Action**: When saving, `setData` with `path: ~.name` and `value: ~.editable_name` copies the edited value back to the original
|
|
239
|
+
5. **Shared Updates**: With `sharedUpdates: true`, changes to `~.name` in the modal propagate back to the row's data
|
|
240
|
+
|
|
241
|
+
## Advantages Over Alternative Approaches
|
|
242
|
+
|
|
243
|
+
### ❌ Complex Approach (Not Recommended)
|
|
244
|
+
- Store file index globally
|
|
245
|
+
- Use custom handlers to find and update array items
|
|
246
|
+
- Requires complex path construction with array indices
|
|
247
|
+
|
|
248
|
+
### ✅ Simple Approach (This Pattern)
|
|
249
|
+
- Modal is in row context - direct access via `~.`
|
|
250
|
+
- No index tracking needed
|
|
251
|
+
- Simple `setData` actions copy values back
|
|
252
|
+
- Works seamlessly with `sharedUpdates`
|
|
253
|
+
|
|
254
|
+
## Best Practices
|
|
255
|
+
|
|
256
|
+
1. **Use `sharedUpdates: true`**: Enables automatic data synchronization between modal and row
|
|
257
|
+
2. **Separate editable fields**: Keep editable copies separate from originals for clean cancel behavior
|
|
258
|
+
3. **Initialize on open**: Copy original values to editable fields when opening the modal
|
|
259
|
+
4. **Simple save pattern**: Use straightforward `setData` actions to copy editable values back
|
|
260
|
+
5. **Row-scoped modals**: Place modals inside row templates to leverage template context
|
|
261
|
+
|
|
262
|
+
## Use Cases
|
|
263
|
+
|
|
264
|
+
- **Data tables**: Edit individual rows without affecting others
|
|
265
|
+
- **List items**: Modify properties of items in a list
|
|
266
|
+
- **Card grids**: Edit cards in a grid layout
|
|
267
|
+
- **Nested data**: Edit nested objects within arrays
|
|
268
|
+
|
|
269
|
+
## Limitations
|
|
270
|
+
|
|
271
|
+
- Each row renders its own modal instance (may impact performance with very large lists)
|
|
272
|
+
- Modal state is tied to row data (if row is removed, modal state is lost)
|
|
273
|
+
- Not suitable for modals that need to persist across row re-renders
|
|
274
|
+
|
|
275
|
+
## Related Patterns
|
|
276
|
+
|
|
277
|
+
- **ReactiveJsonSubroot**: Component used to embed the modal
|
|
278
|
+
- **Switch**: Component used to render rows with templates
|
|
279
|
+
- **setData**: Reaction used to save edited values
|
|
280
|
+
- **sharedUpdates**: Feature enabling bidirectional data sync
|
|
281
|
+
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
renderView:
|
|
2
|
+
- type: Markdown
|
|
3
|
+
content: |
|
|
4
|
+
# Editable Modal in Row Template
|
|
5
|
+
|
|
6
|
+
This guide demonstrates a pattern for creating editable modals within row templates, allowing users to edit individual items in a list without complex state management or custom handlers.
|
|
7
|
+
|
|
8
|
+
## Core Concept
|
|
9
|
+
|
|
10
|
+
By placing a modal inside a row template (using `Switch`), each row gets its own modal instance with direct access to the row's data via the `~.` notation. This simplifies data flow and eliminates the need for complex index tracking or custom save handlers.
|
|
11
|
+
|
|
12
|
+
- type: Markdown
|
|
13
|
+
content: |
|
|
14
|
+
## Key Benefits
|
|
15
|
+
|
|
16
|
+
1. **Simplified data access**: Modal has direct access to row data via `~.` notation
|
|
17
|
+
2. **No index tracking**: No need to find array indices or store file IDs
|
|
18
|
+
3. **Automatic isolation**: Each row's modal is isolated from others
|
|
19
|
+
4. **Simple save pattern**: Use basic `setData` reactions to copy editable values back to originals
|
|
20
|
+
|
|
21
|
+
- type: Markdown
|
|
22
|
+
content: |
|
|
23
|
+
## Prerequisites
|
|
24
|
+
|
|
25
|
+
Before implementing this pattern, you need:
|
|
26
|
+
|
|
27
|
+
1. **A Reactive-JSON Modal component**: This pattern requires a Modal component implementation that supports:
|
|
28
|
+
- `showBoolPath` property (or equivalent) to control visibility via data path
|
|
29
|
+
- `headerTitle` property for the modal header
|
|
30
|
+
- `body` property for the modal content
|
|
31
|
+
- Integration with Reactive-JSON's action system
|
|
32
|
+
|
|
33
|
+
You can use a custom Modal component or one from an integration package (like `@ea-lab/reactive-json-bootstrap`), but it must be compatible with Reactive-JSON's component system.
|
|
34
|
+
|
|
35
|
+
- type: Markdown
|
|
36
|
+
content: |
|
|
37
|
+
## Pattern Structure
|
|
38
|
+
|
|
39
|
+
### 1. Modal Inside Row Template
|
|
40
|
+
|
|
41
|
+
Place the modal component inside your row template so each rendered row has its own modal instance.
|
|
42
|
+
|
|
43
|
+
- type: SyntaxHighlighter
|
|
44
|
+
language: yaml
|
|
45
|
+
title: "Modal Inside Row Template"
|
|
46
|
+
content: |
|
|
47
|
+
templates:
|
|
48
|
+
itemRow:
|
|
49
|
+
- type: tr
|
|
50
|
+
content:
|
|
51
|
+
# Row content (cells, buttons, etc.)
|
|
52
|
+
- type: button
|
|
53
|
+
content: "Edit"
|
|
54
|
+
actions:
|
|
55
|
+
- what: setData
|
|
56
|
+
on: click
|
|
57
|
+
path: ~.showModal
|
|
58
|
+
value: true
|
|
59
|
+
|
|
60
|
+
# Modal inside the row
|
|
61
|
+
- type: ReactiveJsonSubroot
|
|
62
|
+
sharedUpdates: true
|
|
63
|
+
rjOptions:
|
|
64
|
+
rjBuildUrl: "/components/EditModal.yaml"
|
|
65
|
+
dataOverride:
|
|
66
|
+
showModal: ~.showModal
|
|
67
|
+
# ... other data
|
|
68
|
+
|
|
69
|
+
- type: Markdown
|
|
70
|
+
content: |
|
|
71
|
+
### 2. Separate Editable Values
|
|
72
|
+
|
|
73
|
+
Use separate fields for editable copies and original values.
|
|
74
|
+
|
|
75
|
+
- type: SyntaxHighlighter
|
|
76
|
+
language: yaml
|
|
77
|
+
title: "Data Override Structure"
|
|
78
|
+
content: |
|
|
79
|
+
dataOverride:
|
|
80
|
+
# Original values (read-only display)
|
|
81
|
+
id: ~.id
|
|
82
|
+
name: ~.name
|
|
83
|
+
|
|
84
|
+
# Editable copies (for form fields)
|
|
85
|
+
editable_name: ~.editable.name
|
|
86
|
+
editable_description: ~.editable.description
|
|
87
|
+
|
|
88
|
+
# Original values (for saving back)
|
|
89
|
+
name: ~.name
|
|
90
|
+
description: ~.description
|
|
91
|
+
|
|
92
|
+
- type: Markdown
|
|
93
|
+
content: |
|
|
94
|
+
### 3. Initialize Editable Values
|
|
95
|
+
|
|
96
|
+
When opening the modal, copy original values to editable fields.
|
|
97
|
+
|
|
98
|
+
- type: SyntaxHighlighter
|
|
99
|
+
language: yaml
|
|
100
|
+
title: "Initialize Editable Values"
|
|
101
|
+
content: |
|
|
102
|
+
- type: button
|
|
103
|
+
content: "Edit"
|
|
104
|
+
actions:
|
|
105
|
+
- what: setData
|
|
106
|
+
on: click
|
|
107
|
+
path: ~.editable.name
|
|
108
|
+
value: ~.name
|
|
109
|
+
- what: setData
|
|
110
|
+
on: click
|
|
111
|
+
path: ~.editable.description
|
|
112
|
+
value: ~.description
|
|
113
|
+
- what: setData
|
|
114
|
+
on: click
|
|
115
|
+
path: ~.showModal
|
|
116
|
+
value: true
|
|
117
|
+
|
|
118
|
+
- type: Markdown
|
|
119
|
+
content: |
|
|
120
|
+
### 4. Save Pattern
|
|
121
|
+
|
|
122
|
+
Use simple `setData` reactions to copy editable values back to originals.
|
|
123
|
+
|
|
124
|
+
- type: SyntaxHighlighter
|
|
125
|
+
language: yaml
|
|
126
|
+
title: "Save Button Actions"
|
|
127
|
+
content: |
|
|
128
|
+
- type: button
|
|
129
|
+
content: "Save"
|
|
130
|
+
actions:
|
|
131
|
+
- what: setData
|
|
132
|
+
on: click
|
|
133
|
+
path: ~.name
|
|
134
|
+
value: ~.editable_name
|
|
135
|
+
- what: setData
|
|
136
|
+
on: click
|
|
137
|
+
path: ~.description
|
|
138
|
+
value: ~.editable_description
|
|
139
|
+
- what: setData
|
|
140
|
+
on: click
|
|
141
|
+
path: ~.showModal
|
|
142
|
+
value: false
|
|
143
|
+
|
|
144
|
+
- type: RjBuildDescriber
|
|
145
|
+
title: "Complete Example: Editable Item List"
|
|
146
|
+
description: |
|
|
147
|
+
A complete example showing a table with editable rows. Each row has an "Edit" button that opens a modal. The modal allows editing the item's name and description, with Save and Cancel buttons.
|
|
148
|
+
toDescribe:
|
|
149
|
+
renderView:
|
|
150
|
+
- type: div
|
|
151
|
+
attributes:
|
|
152
|
+
class: "p-4"
|
|
153
|
+
content:
|
|
154
|
+
- type: h2
|
|
155
|
+
attributes:
|
|
156
|
+
class: "text-2xl font-bold mb-4"
|
|
157
|
+
content: "Items List"
|
|
158
|
+
- type: table
|
|
159
|
+
attributes:
|
|
160
|
+
class: "w-full border-collapse border border-gray-300"
|
|
161
|
+
content:
|
|
162
|
+
- type: thead
|
|
163
|
+
content:
|
|
164
|
+
- type: tr
|
|
165
|
+
content:
|
|
166
|
+
- type: th
|
|
167
|
+
attributes:
|
|
168
|
+
class: "border border-gray-300 p-2 bg-gray-100"
|
|
169
|
+
content: "ID"
|
|
170
|
+
- type: th
|
|
171
|
+
attributes:
|
|
172
|
+
class: "border border-gray-300 p-2 bg-gray-100"
|
|
173
|
+
content: "Name"
|
|
174
|
+
- type: th
|
|
175
|
+
attributes:
|
|
176
|
+
class: "border border-gray-300 p-2 bg-gray-100"
|
|
177
|
+
content: "Description"
|
|
178
|
+
- type: th
|
|
179
|
+
attributes:
|
|
180
|
+
class: "border border-gray-300 p-2 bg-gray-100"
|
|
181
|
+
content: "Actions"
|
|
182
|
+
- type: tbody
|
|
183
|
+
content:
|
|
184
|
+
- type: Switch
|
|
185
|
+
content: ~~.items
|
|
186
|
+
singleOption:
|
|
187
|
+
load: itemRow
|
|
188
|
+
- type: div
|
|
189
|
+
attributes:
|
|
190
|
+
class: "mt-4 p-2 bg-gray-100 rounded"
|
|
191
|
+
content:
|
|
192
|
+
- type: strong
|
|
193
|
+
content: "Debug - First item name: "
|
|
194
|
+
- type: span
|
|
195
|
+
content: ~~.items.0.name
|
|
196
|
+
|
|
197
|
+
templates:
|
|
198
|
+
itemRow:
|
|
199
|
+
- type: tr
|
|
200
|
+
content:
|
|
201
|
+
- type: td
|
|
202
|
+
attributes:
|
|
203
|
+
class: "border border-gray-300 p-2"
|
|
204
|
+
content: ~.id
|
|
205
|
+
- type: td
|
|
206
|
+
attributes:
|
|
207
|
+
class: "border border-gray-300 p-2"
|
|
208
|
+
content: ~.name
|
|
209
|
+
- type: td
|
|
210
|
+
attributes:
|
|
211
|
+
class: "border border-gray-300 p-2"
|
|
212
|
+
content: ~.description
|
|
213
|
+
- type: td
|
|
214
|
+
attributes:
|
|
215
|
+
class: "border border-gray-300 p-2"
|
|
216
|
+
content:
|
|
217
|
+
- type: button
|
|
218
|
+
attributes:
|
|
219
|
+
class: "bg-blue-500 text-white px-3 py-1 rounded hover:bg-blue-600"
|
|
220
|
+
content: "Edit"
|
|
221
|
+
actions:
|
|
222
|
+
- what: setData
|
|
223
|
+
on: click
|
|
224
|
+
path: ~.editable.name
|
|
225
|
+
value: ~.name
|
|
226
|
+
- what: setData
|
|
227
|
+
on: click
|
|
228
|
+
path: ~.editable.description
|
|
229
|
+
value: ~.description
|
|
230
|
+
- what: setData
|
|
231
|
+
on: click
|
|
232
|
+
path: ~.showModal
|
|
233
|
+
value: true
|
|
234
|
+
|
|
235
|
+
# Modal inside the row
|
|
236
|
+
- type: ReactiveJsonSubroot
|
|
237
|
+
sharedUpdates: true
|
|
238
|
+
rjOptions:
|
|
239
|
+
maybeRawAppRjBuild:
|
|
240
|
+
renderView:
|
|
241
|
+
- type: Modal
|
|
242
|
+
showBoolPath: ~.showModal
|
|
243
|
+
headerTitle:
|
|
244
|
+
type: h3
|
|
245
|
+
attributes:
|
|
246
|
+
class: "text-xl font-semibold"
|
|
247
|
+
content: "Edit Item"
|
|
248
|
+
body:
|
|
249
|
+
- type: div
|
|
250
|
+
attributes:
|
|
251
|
+
class: "space-y-4"
|
|
252
|
+
content:
|
|
253
|
+
- type: div
|
|
254
|
+
content:
|
|
255
|
+
- type: label
|
|
256
|
+
attributes:
|
|
257
|
+
class: "block text-sm font-medium mb-1"
|
|
258
|
+
content: "ID (read-only):"
|
|
259
|
+
- type: div
|
|
260
|
+
attributes:
|
|
261
|
+
class: "p-2 bg-gray-100 rounded"
|
|
262
|
+
content: ~.id
|
|
263
|
+
- type: div
|
|
264
|
+
content:
|
|
265
|
+
- type: label
|
|
266
|
+
attributes:
|
|
267
|
+
class: "block text-sm font-medium mb-1"
|
|
268
|
+
content: "Name:"
|
|
269
|
+
- type: TextField
|
|
270
|
+
dataLocation: ~.editable_name
|
|
271
|
+
forceWrapper: false
|
|
272
|
+
inputAttributes:
|
|
273
|
+
class: "w-full p-2 border border-gray-300 rounded"
|
|
274
|
+
- type: div
|
|
275
|
+
content:
|
|
276
|
+
- type: label
|
|
277
|
+
attributes:
|
|
278
|
+
class: "block text-sm font-medium mb-1"
|
|
279
|
+
content: "Description:"
|
|
280
|
+
- type: TextAreaField
|
|
281
|
+
dataLocation: ~.editable_description
|
|
282
|
+
forceWrapper: false
|
|
283
|
+
rows: 3
|
|
284
|
+
inputAttributes:
|
|
285
|
+
class: "w-full p-2 border border-gray-300 rounded"
|
|
286
|
+
- type: div
|
|
287
|
+
attributes:
|
|
288
|
+
class: "flex justify-end gap-2 mt-4 pt-4 border-t border-gray-200 dark:border-gray-700"
|
|
289
|
+
content:
|
|
290
|
+
- type: button
|
|
291
|
+
attributes:
|
|
292
|
+
class: "px-4 py-2 bg-gray-300 rounded hover:bg-gray-400"
|
|
293
|
+
content: "Cancel"
|
|
294
|
+
actions:
|
|
295
|
+
- what: setData
|
|
296
|
+
on: click
|
|
297
|
+
path: ~.showModal
|
|
298
|
+
value: false
|
|
299
|
+
- type: button
|
|
300
|
+
attributes:
|
|
301
|
+
class: "px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
|
302
|
+
content: "Save"
|
|
303
|
+
actions:
|
|
304
|
+
- what: setData
|
|
305
|
+
on: click
|
|
306
|
+
path: ~.name
|
|
307
|
+
value: ~.editable_name
|
|
308
|
+
- what: setData
|
|
309
|
+
on: click
|
|
310
|
+
path: ~.description
|
|
311
|
+
value: ~.editable_description
|
|
312
|
+
- what: setData
|
|
313
|
+
on: click
|
|
314
|
+
path: ~.showModal
|
|
315
|
+
value: false
|
|
316
|
+
data:
|
|
317
|
+
showModal: false
|
|
318
|
+
id: ""
|
|
319
|
+
name: ""
|
|
320
|
+
editable_name: ""
|
|
321
|
+
editable_description: ""
|
|
322
|
+
description: ""
|
|
323
|
+
dataOverride:
|
|
324
|
+
showModal: ~.showModal
|
|
325
|
+
id: ~.id
|
|
326
|
+
name: ~.name
|
|
327
|
+
editable_name: ~.editable.name
|
|
328
|
+
editable_description: ~.editable.description
|
|
329
|
+
description: ~.description
|
|
330
|
+
|
|
331
|
+
data:
|
|
332
|
+
items:
|
|
333
|
+
- id: 1
|
|
334
|
+
name: "First Item"
|
|
335
|
+
description: "This is the first item's description"
|
|
336
|
+
showModal: false
|
|
337
|
+
editable:
|
|
338
|
+
name: ""
|
|
339
|
+
description: ""
|
|
340
|
+
- id: 2
|
|
341
|
+
name: "Second Item"
|
|
342
|
+
description: "This is the second item's description"
|
|
343
|
+
showModal: false
|
|
344
|
+
editable:
|
|
345
|
+
name: ""
|
|
346
|
+
description: ""
|
|
347
|
+
- id: 3
|
|
348
|
+
name: "Third Item"
|
|
349
|
+
description: "This is the third item's description"
|
|
350
|
+
showModal: false
|
|
351
|
+
editable:
|
|
352
|
+
name: ""
|
|
353
|
+
description: ""
|
|
354
|
+
|
|
355
|
+
- type: Markdown
|
|
356
|
+
content: |
|
|
357
|
+
## How It Works
|
|
358
|
+
|
|
359
|
+
1. **Row Context**: Each row rendered by `Switch` has its own template context, accessible via `~.`
|
|
360
|
+
2. **Modal Access**: The modal inside the row inherits this context, so `~.name` refers to the current row's name
|
|
361
|
+
3. **Editable Copies**: Form fields bind to `~.editable_name` (or `~.editable.name`), keeping edits separate from originals
|
|
362
|
+
4. **Save Action**: When saving, `setData` with `path: ~.name` and `value: ~.editable_name` copies the edited value back to the original
|
|
363
|
+
5. **Shared Updates**: With `sharedUpdates: true`, changes to `~.name` in the modal propagate back to the row's data
|
|
364
|
+
|
|
365
|
+
- type: Markdown
|
|
366
|
+
content: |
|
|
367
|
+
## Advantages Over Alternative Approaches
|
|
368
|
+
|
|
369
|
+
### ❌ Complex Approach (Not Recommended)
|
|
370
|
+
- Store file index globally
|
|
371
|
+
- Use custom handlers to find and update array items
|
|
372
|
+
- Requires complex path construction with array indices
|
|
373
|
+
|
|
374
|
+
### ✅ Simple Approach (This Pattern)
|
|
375
|
+
- Modal is in row context - direct access via `~.`
|
|
376
|
+
- No index tracking needed
|
|
377
|
+
- Simple `setData` actions copy values back
|
|
378
|
+
- Works seamlessly with `sharedUpdates`
|
|
379
|
+
|
|
380
|
+
- type: Markdown
|
|
381
|
+
content: |
|
|
382
|
+
## Best Practices
|
|
383
|
+
|
|
384
|
+
1. **Use `sharedUpdates: true`**: Enables automatic data synchronization between modal and row
|
|
385
|
+
2. **Separate editable fields**: Keep editable copies separate from originals for clean cancel behavior
|
|
386
|
+
3. **Initialize on open**: Copy original values to editable fields when opening the modal
|
|
387
|
+
4. **Simple save pattern**: Use straightforward `setData` actions to copy editable values back
|
|
388
|
+
5. **Row-scoped modals**: Place modals inside row templates to leverage template context
|
|
389
|
+
|
|
390
|
+
- type: Markdown
|
|
391
|
+
content: |
|
|
392
|
+
## Use Cases
|
|
393
|
+
|
|
394
|
+
- **Data tables**: Edit individual rows without affecting others
|
|
395
|
+
- **List items**: Modify properties of items in a list
|
|
396
|
+
- **Card grids**: Edit cards in a grid layout
|
|
397
|
+
- **Nested data**: Edit nested objects within arrays
|
|
398
|
+
|
|
399
|
+
- type: Markdown
|
|
400
|
+
content: |
|
|
401
|
+
## Limitations
|
|
402
|
+
|
|
403
|
+
- Each row renders its own modal instance (may impact performance with very large lists)
|
|
404
|
+
- Modal state is tied to row data (if row is removed, modal state is lost)
|
|
405
|
+
- Not suitable for modals that need to persist across row re-renders
|
|
406
|
+
|
|
407
|
+
- type: Markdown
|
|
408
|
+
content: |
|
|
409
|
+
## Related Patterns
|
|
410
|
+
|
|
411
|
+
- **ReactiveJsonSubroot**: Component used to embed the modal
|
|
412
|
+
- **Switch**: Component used to render rows with templates
|
|
413
|
+
- **setData**: Reaction used to save edited values
|
|
414
|
+
- **sharedUpdates**: Feature enabling bidirectional data sync
|
|
415
|
+
|