@ea-lab/reactive-json-docs 2.8.0 → 2.10.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 +142 -18
- package/public/rjbuild/docs/core/element/form/CheckBoxField.yaml +132 -7
- package/public/rjbuild/docs/core/element/form/SelectField.md +36 -10
- package/public/rjbuild/docs/core/element/form/SelectField.yaml +37 -3
- package/public/rjbuild/docs/core/element/form/formElementsCommon.md +32 -0
- package/public/rjbuild/docs/core/element/html/Html.yaml +47 -0
- package/public/rjbuild/docs/core/element/html/LabelFromValue.md +159 -0
- package/public/rjbuild/docs/core/element/html/LabelFromValue.yaml +163 -10
- package/public/rjbuild/docs/core/example/native-html-forms.md +19 -2
- package/public/rjbuild/docs/core/reaction/collectField.md +51 -0
- package/public/rjbuild/docs/core/reaction/collectField.yaml +81 -0
- package/public/rjbuild/docs/core/reaction/fetchData.md +21 -1
- package/public/rjbuild/docs/core/reaction/fetchData.yaml +2 -2
- package/public/rjbuild/docs/core/reaction/index.md +5 -0
- package/public/rjbuild/docs/core/reaction/index.yaml +5 -0
- package/public/rjbuild/docs/core/reaction/joinData.md +51 -0
- package/public/rjbuild/docs/core/reaction/joinData.yaml +87 -0
- package/public/rjbuild/docs/core/reaction/printPage.md +22 -0
- package/public/rjbuild/docs/core/reaction/printPage.yaml +29 -0
- package/public/rjbuild/docs/core/reaction/redirectNow.md +20 -2
- package/public/rjbuild/docs/core/reaction/redirectNow.yaml +24 -3
- package/public/rjbuild/docs/core/reaction/setClipboardData.md +35 -6
- package/public/rjbuild/docs/core/reaction/setClipboardData.yaml +18 -6
- package/public/rjbuild/docs/core/reaction/stringifyData.md +45 -0
- package/public/rjbuild/docs/core/reaction/stringifyData.yaml +58 -0
- package/public/rjbuild/docs/core/reaction/submitData.md +1 -1
- package/public/rjbuild/docs/core/reaction/submitData.yaml +4 -2
- package/public/rjbuild/docs/core/reaction/toggleData.md +72 -0
- package/public/rjbuild/docs/core/reaction/toggleData.yaml +77 -0
- package/public/rjbuild/docs/getting-started/reactions.md +5 -0
- package/public/rjbuild/docs/getting-started/reactions.yaml +5 -0
- package/public/rjbuild/docs/getting-started/rjbuild-structure.md +19 -1
- package/public/rjbuild/docs/getting-started/rjbuild-structure.yaml +21 -1
|
@@ -74,6 +74,53 @@ renderView:
|
|
|
74
74
|
class: ""
|
|
75
75
|
txt: Hello world!
|
|
76
76
|
|
|
77
|
+
- type: Markdown
|
|
78
|
+
content: |
|
|
79
|
+
## URL attributes
|
|
80
|
+
|
|
81
|
+
The URL attributes (`href`, `src`, `action`, `formAction`, `poster`) accept an array of segments, in the format of the `src` of `additionalDataSource` (see *Dynamic URLs with `src` as Array* in [RjBuild structure](../../getting-started/rjbuild-structure)). The references are evaluated in the current template context, so each item of a `Switch` gets its own URL:
|
|
82
|
+
|
|
83
|
+
```yaml
|
|
84
|
+
- type: a
|
|
85
|
+
attributes:
|
|
86
|
+
href:
|
|
87
|
+
- "/article/"
|
|
88
|
+
- ~.year
|
|
89
|
+
- "/"
|
|
90
|
+
- segment: ~.slug
|
|
91
|
+
required: true
|
|
92
|
+
content: ~.title
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
When a required segment is empty, the attribute is omitted. An array in another attribute is evaluated as before (each item separately).
|
|
96
|
+
|
|
97
|
+
- type: Markdown
|
|
98
|
+
content: |
|
|
99
|
+
## Form controls
|
|
100
|
+
|
|
101
|
+
`input`, `textarea` and `select` elements are rendered as **controlled** React elements: their `value` defaults to `""`.
|
|
102
|
+
|
|
103
|
+
A checkbox or radio `input` is controlled by its `checked` attribute, which defaults to `false`. Without a binding, the input never shows as checked, whatever its reactions do to the data. Bind it to the data:
|
|
104
|
+
|
|
105
|
+
- a boolean: `checked: ~.isSelected` (a falsy value leaves the input unchecked);
|
|
106
|
+
- a comparison or a list membership: an `attributeTransforms` entry setting `checked`, with a condition (`is`, `contains`...).
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
- type: input
|
|
110
|
+
attributes:
|
|
111
|
+
type: checkbox
|
|
112
|
+
value: ~.label
|
|
113
|
+
attributeTransforms:
|
|
114
|
+
- what: setAttributeValue
|
|
115
|
+
name: checked
|
|
116
|
+
mode: replace
|
|
117
|
+
value: true
|
|
118
|
+
when: ~~.lead.sessions
|
|
119
|
+
contains: ~.label
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
A warning is logged when a checkbox or radio has event reactions (`on: change`...) but neither a `checked` attribute nor an attribute transform on `checked`. To store a value or a list of values, prefer [CheckBoxField](../form/CheckBoxField), which binds `checked` itself.
|
|
123
|
+
|
|
77
124
|
- type: Markdown
|
|
78
125
|
content: |
|
|
79
126
|
## Limitations
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# LabelFromValue
|
|
2
|
+
|
|
3
|
+
The `LabelFromValue` component displays the **label** associated with a value, using an option-like structure as data source. It is the read-only counterpart of the form fields: the same `{label, value}` list feeding a [`SelectField`](../form/SelectField.md) or a [`CheckBoxField`](../form/CheckBoxField.md) can be reused to render the selected value as text.
|
|
4
|
+
|
|
5
|
+
## Basic Syntax
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
- type: LabelFromValue
|
|
9
|
+
dataLocation: ~.status
|
|
10
|
+
options:
|
|
11
|
+
- label: "Active"
|
|
12
|
+
value: 1
|
|
13
|
+
- label: "Inactive"
|
|
14
|
+
value: 2
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
With `status: 2` in the data, this renders `Inactive`.
|
|
18
|
+
|
|
19
|
+
## Properties
|
|
20
|
+
|
|
21
|
+
- `dataLocation` (string, optional): Path to the value to resolve. Without it, the value is read from the template context under the component's `datafield`.
|
|
22
|
+
- `options` (array, optional): Array of `{label, value}` objects (both support template evaluation). Ignored when `dynamicOptions` is set.
|
|
23
|
+
- `dynamicOptions` (any, optional): Template reference resolving to the options array (e.g. `~~.allStages`, typically options loaded from a backend). Takes precedence over `options`. The items can be `{label, value}` objects, scalars (each scalar is used as both label and value), or objects of any shape mapped with `optionMapping`.
|
|
24
|
+
- `optionMapping` (object, optional): Builds each option from an item of the options list, exactly like in `SelectField` and `CheckBoxField`. It is evaluated once per item, **with the item as the template context** (`~.title` reads the item's `title`, `~~.` still reads the global data). The mapped keys override the item's keys.
|
|
25
|
+
- `defaultFieldValue` (any, optional): Value used when no data is present.
|
|
26
|
+
- `loose` (boolean, optional): Matches the options by `String()`-coerced equality instead of the default strict one (see [Loose matching](#loose-matching)). Omitted or `false` = strict equality (original behavior).
|
|
27
|
+
- `actions` (array, optional): Actions and conditional reactions to execute based on component state (hide, tooltip, …).
|
|
28
|
+
|
|
29
|
+
The label is rendered through the `View` engine, so it can be a plain string or a full component structure (`{type: strong, content: …}`).
|
|
30
|
+
|
|
31
|
+
## Loose matching
|
|
32
|
+
|
|
33
|
+
By default an option matches the current value only on **strict** equality (`===`), so `1` (number) and `"1"` (string) are two different values and no label is found.
|
|
34
|
+
|
|
35
|
+
This bites when the JS type of the same identifier is not guaranteed across sources. A typical case is a decoupled backend that renders an entity reference id as a **string** when reading the entity, but echoes it back as a **number** in its save response: the label is correct on load, then disappears right after a save — until a full reload restores the original type.
|
|
36
|
+
|
|
37
|
+
Set `loose: true` to compare the values as strings instead:
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
- type: LabelFromValue
|
|
41
|
+
dataLocation: ~.stage
|
|
42
|
+
dynamicOptions: ~~.allStages
|
|
43
|
+
loose: true
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Nullish values are never coerced: an empty value (`null` / `undefined`) still matches nothing, so it cannot accidentally match an option whose value is the `"null"` string. `loose` is opt-in — omitted, the component behaves exactly as before, so existing usages are unaffected.
|
|
47
|
+
|
|
48
|
+
## Examples
|
|
49
|
+
|
|
50
|
+
### Display the label of a selected value
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
renderView:
|
|
54
|
+
- type: SelectField
|
|
55
|
+
dataLocation: ~.status
|
|
56
|
+
label: "Status"
|
|
57
|
+
options:
|
|
58
|
+
- label: "Active"
|
|
59
|
+
value: 1
|
|
60
|
+
- label: "Inactive"
|
|
61
|
+
value: 2
|
|
62
|
+
- label: "Pending"
|
|
63
|
+
value: 3
|
|
64
|
+
- type: div
|
|
65
|
+
content:
|
|
66
|
+
- type: strong
|
|
67
|
+
content: "Label: "
|
|
68
|
+
- type: LabelFromValue
|
|
69
|
+
dataLocation: ~.status
|
|
70
|
+
options:
|
|
71
|
+
- label: "Active"
|
|
72
|
+
value: 1
|
|
73
|
+
- label: "Inactive"
|
|
74
|
+
value: 2
|
|
75
|
+
- label: "Pending"
|
|
76
|
+
value: 3
|
|
77
|
+
|
|
78
|
+
data:
|
|
79
|
+
status: 3
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Renders: `Label: Pending`.
|
|
83
|
+
|
|
84
|
+
### Options loaded from a backend, with loose matching
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
renderView:
|
|
88
|
+
- type: LabelFromValue
|
|
89
|
+
dataLocation: ~~.deal.data.stage
|
|
90
|
+
dynamicOptions: ~~.allStages
|
|
91
|
+
loose: true
|
|
92
|
+
|
|
93
|
+
data:
|
|
94
|
+
# allStages is typically fetched (additionalDataSource) as
|
|
95
|
+
# [{label: "Discovery", value: "12"}, {label: "Negotiation", value: "13"}, …]
|
|
96
|
+
deal:
|
|
97
|
+
data:
|
|
98
|
+
stage: 13
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The value is a number while the option values are strings: without `loose`, nothing would be displayed.
|
|
102
|
+
|
|
103
|
+
### Options of any shape, with a mapping
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
106
|
+
renderView:
|
|
107
|
+
- type: LabelFromValue
|
|
108
|
+
dataLocation: ~~.deal.stage
|
|
109
|
+
dynamicOptions: ~~.stages
|
|
110
|
+
optionMapping:
|
|
111
|
+
label: ~.title
|
|
112
|
+
value: ~.id
|
|
113
|
+
|
|
114
|
+
data:
|
|
115
|
+
stages:
|
|
116
|
+
- id: "new"
|
|
117
|
+
title: "New"
|
|
118
|
+
- id: "won"
|
|
119
|
+
title: "Won"
|
|
120
|
+
deal:
|
|
121
|
+
stage: "won"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Renders: `Won`. Use the same `optionMapping` as the `SelectField` editing the value.
|
|
125
|
+
|
|
126
|
+
### Inside a template, against global data
|
|
127
|
+
|
|
128
|
+
```yaml
|
|
129
|
+
templates:
|
|
130
|
+
userCard:
|
|
131
|
+
type: div
|
|
132
|
+
content:
|
|
133
|
+
- "Admin: "
|
|
134
|
+
- type: LabelFromValue
|
|
135
|
+
dataLocation: ~~.isAdmin
|
|
136
|
+
options:
|
|
137
|
+
- label: "Yes"
|
|
138
|
+
value: true
|
|
139
|
+
- label: "No"
|
|
140
|
+
value: false
|
|
141
|
+
|
|
142
|
+
renderView:
|
|
143
|
+
- load: userCard
|
|
144
|
+
|
|
145
|
+
data:
|
|
146
|
+
isAdmin: true
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Notes
|
|
150
|
+
|
|
151
|
+
- The first matching option wins; the options list is not deduplicated.
|
|
152
|
+
- When no option matches the value (or the matched option carries no `label`), nothing is displayed — the value itself is not used as a fallback label.
|
|
153
|
+
- An empty value (`null`, `undefined`, `""`) therefore renders nothing, unless an option explicitly declares that value.
|
|
154
|
+
|
|
155
|
+
## Limitations
|
|
156
|
+
|
|
157
|
+
- No support for grouped options or nested option structures.
|
|
158
|
+
- No built-in formatting of the label (wrap the component if needed).
|
|
159
|
+
- Multi-value data (an array of values) is not supported: the whole array is compared to each option value.
|
|
@@ -3,7 +3,23 @@ renderView:
|
|
|
3
3
|
content: |
|
|
4
4
|
# LabelFromValue
|
|
5
5
|
|
|
6
|
-
The `LabelFromValue` component displays the label associated with a value, using an option-like structure. It is
|
|
6
|
+
The `LabelFromValue` component displays the **label** associated with a value, using an option-like structure as data source. It is the read-only counterpart of the form fields: the same `{label, value}` list feeding a [`SelectField`](/docs/core/element/form/SelectField) or a [`CheckBoxField`](/docs/core/element/form/CheckBoxField) can be reused to render the selected value as text.
|
|
7
|
+
|
|
8
|
+
- type: Markdown
|
|
9
|
+
content: |
|
|
10
|
+
## Basic Syntax
|
|
11
|
+
|
|
12
|
+
```yaml
|
|
13
|
+
- type: LabelFromValue
|
|
14
|
+
dataLocation: ~.status
|
|
15
|
+
options:
|
|
16
|
+
- label: "Active"
|
|
17
|
+
value: 1
|
|
18
|
+
- label: "Inactive"
|
|
19
|
+
value: 2
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
With `status: 2` in the data, this renders `Inactive`.
|
|
7
23
|
|
|
8
24
|
## Properties
|
|
9
25
|
|
|
@@ -11,22 +27,44 @@ renderView:
|
|
|
11
27
|
content:
|
|
12
28
|
- term:
|
|
13
29
|
code: dataLocation
|
|
14
|
-
after: "(string,
|
|
15
|
-
details: "Path to the value."
|
|
30
|
+
after: "(string, optional)"
|
|
31
|
+
details: "Path to the value to resolve. Without it, the value is read from the template context under the component's `datafield`."
|
|
16
32
|
- term:
|
|
17
33
|
code: options
|
|
18
34
|
after: "(array, optional)"
|
|
19
35
|
details:
|
|
20
36
|
type: Markdown
|
|
21
|
-
content: "Array of `{label, value}` objects."
|
|
37
|
+
content: "Array of `{label, value}` objects (both support template evaluation). Ignored when `dynamicOptions` is set."
|
|
22
38
|
- term:
|
|
23
39
|
code: dynamicOptions
|
|
24
40
|
after: "(any, optional)"
|
|
25
|
-
details:
|
|
41
|
+
details:
|
|
42
|
+
type: Markdown
|
|
43
|
+
content: "Template reference resolving to the options array (e.g. `~~.allStages`, typically options loaded from a backend). Takes precedence over `options`. The items can be `{label, value}` objects, scalars (each scalar is used as both label and value), or objects of any shape mapped with `optionMapping`."
|
|
44
|
+
- term:
|
|
45
|
+
code: optionMapping
|
|
46
|
+
after: "(object, optional)"
|
|
47
|
+
details:
|
|
48
|
+
type: Markdown
|
|
49
|
+
content: "Builds each option from an item of the options list, exactly like in `SelectField` and `CheckBoxField`. It is evaluated once per item, **with the item as the template context** (`~.title` reads the item's `title`, `~~.` still reads the global data). The mapped keys override the item's keys."
|
|
26
50
|
- term:
|
|
27
51
|
code: defaultFieldValue
|
|
28
52
|
after: "(any, optional)"
|
|
29
|
-
details: "
|
|
53
|
+
details: "Value used when no data is present."
|
|
54
|
+
- term:
|
|
55
|
+
code: loose
|
|
56
|
+
after: "(boolean, optional)"
|
|
57
|
+
details:
|
|
58
|
+
type: Markdown
|
|
59
|
+
content: "Matches the options by `String()`-coerced equality instead of the default strict one. See [Loose matching](#loose-matching). Omitted or `false` = strict equality (original behavior)."
|
|
60
|
+
- term:
|
|
61
|
+
code: actions
|
|
62
|
+
after: "(array, optional)"
|
|
63
|
+
details: "Actions and conditional reactions to execute based on component state (hide, tooltip, …)."
|
|
64
|
+
|
|
65
|
+
- type: Markdown
|
|
66
|
+
content: |
|
|
67
|
+
The label is rendered through the `View` engine, so it can be a plain string or a full component structure (`{type: strong, content: …}`).
|
|
30
68
|
|
|
31
69
|
- type: RjBuildDescriber
|
|
32
70
|
title: "Interactive Example: Display label from value"
|
|
@@ -64,8 +102,123 @@ renderView:
|
|
|
64
102
|
|
|
65
103
|
- type: Markdown
|
|
66
104
|
content: |
|
|
105
|
+
## Loose matching
|
|
106
|
+
|
|
107
|
+
By default an option matches the current value only on **strict** equality (`===`), so `1` (number) and `"1"` (string) are two different values and no label is found.
|
|
108
|
+
|
|
109
|
+
This bites when the JS type of the same identifier is not guaranteed across sources. A typical case is a decoupled backend that renders an entity reference id as a **string** when reading the entity, but echoes it back as a **number** in its save response: the label is correct on load, then disappears right after a save — until a full reload restores the original type.
|
|
110
|
+
|
|
111
|
+
Set `loose: true` to compare the values as strings instead:
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
- type: LabelFromValue
|
|
115
|
+
dataLocation: ~.stage
|
|
116
|
+
dynamicOptions: ~~.allStages
|
|
117
|
+
loose: true
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Nullish values are never coerced: an empty value (`null` / `undefined`) still matches nothing, so it cannot accidentally match an option whose value is the `"null"` string. `loose` is opt-in — omitted, the component behaves exactly as before.
|
|
121
|
+
|
|
122
|
+
- type: RjBuildDescriber
|
|
123
|
+
title: "Interactive Example: Loose matching"
|
|
124
|
+
description:
|
|
125
|
+
- type: Markdown
|
|
126
|
+
content: |
|
|
127
|
+
Both components read the same value, `"2"` (a **string**), against options whose values are **numbers**. Only the loose one finds the label.
|
|
128
|
+
toDescribe:
|
|
129
|
+
renderView:
|
|
130
|
+
- type: div
|
|
131
|
+
content:
|
|
132
|
+
- type: strong
|
|
133
|
+
content: "Strict (default): "
|
|
134
|
+
- type: LabelFromValue
|
|
135
|
+
dataLocation: ~.status
|
|
136
|
+
options:
|
|
137
|
+
- label: "Active"
|
|
138
|
+
value: 1
|
|
139
|
+
- label: "Inactive"
|
|
140
|
+
value: 2
|
|
141
|
+
- label: "Pending"
|
|
142
|
+
value: 3
|
|
143
|
+
- type: div
|
|
144
|
+
content:
|
|
145
|
+
- type: strong
|
|
146
|
+
content: "Loose: "
|
|
147
|
+
- type: LabelFromValue
|
|
148
|
+
dataLocation: ~.status
|
|
149
|
+
loose: true
|
|
150
|
+
options:
|
|
151
|
+
- label: "Active"
|
|
152
|
+
value: 1
|
|
153
|
+
- label: "Inactive"
|
|
154
|
+
value: 2
|
|
155
|
+
- label: "Pending"
|
|
156
|
+
value: 3
|
|
157
|
+
data:
|
|
158
|
+
status: "2"
|
|
159
|
+
|
|
160
|
+
- type: RjBuildDescriber
|
|
161
|
+
title: "Interactive Example: Options loaded from a backend"
|
|
162
|
+
description:
|
|
163
|
+
- type: Markdown
|
|
164
|
+
content: |
|
|
165
|
+
`dynamicOptions` reads the options from the data (here `allStages`, as an `additionalDataSource` would provide them). The value is a **number** while the option values are **strings**, hence `loose: true`.
|
|
166
|
+
toDescribe:
|
|
167
|
+
renderView:
|
|
168
|
+
- type: div
|
|
169
|
+
content:
|
|
170
|
+
- type: strong
|
|
171
|
+
content: "Stage: "
|
|
172
|
+
- type: LabelFromValue
|
|
173
|
+
dataLocation: ~~.deal.data.stage
|
|
174
|
+
dynamicOptions: ~~.allStages
|
|
175
|
+
loose: true
|
|
176
|
+
data:
|
|
177
|
+
allStages:
|
|
178
|
+
- label: "Discovery"
|
|
179
|
+
value: "12"
|
|
180
|
+
- label: "Negotiation"
|
|
181
|
+
value: "13"
|
|
182
|
+
- label: "Closed won"
|
|
183
|
+
value: "14"
|
|
184
|
+
deal:
|
|
185
|
+
data:
|
|
186
|
+
stage: 13
|
|
187
|
+
|
|
188
|
+
- type: RjBuildDescriber
|
|
189
|
+
title: "Interactive Example: Inside a template, against global data"
|
|
190
|
+
description:
|
|
191
|
+
- type: Markdown
|
|
192
|
+
content: |
|
|
193
|
+
Within a template, `~~.` reaches the global data while `~.` would stay in the template scope.
|
|
194
|
+
toDescribe:
|
|
195
|
+
renderView:
|
|
196
|
+
- load: userCard
|
|
197
|
+
templates:
|
|
198
|
+
userCard:
|
|
199
|
+
type: div
|
|
200
|
+
content:
|
|
201
|
+
- "Admin: "
|
|
202
|
+
- type: LabelFromValue
|
|
203
|
+
dataLocation: ~~.isAdmin
|
|
204
|
+
options:
|
|
205
|
+
- label: "Yes"
|
|
206
|
+
value: true
|
|
207
|
+
- label: "No"
|
|
208
|
+
value: false
|
|
209
|
+
data:
|
|
210
|
+
isAdmin: true
|
|
211
|
+
|
|
212
|
+
- type: Markdown
|
|
213
|
+
content: |
|
|
214
|
+
## Notes
|
|
215
|
+
|
|
216
|
+
- The first matching option wins; the options list is not deduplicated.
|
|
217
|
+
- When no option matches the value (or the matched option carries no `label`), nothing is displayed — the value itself is not used as a fallback label.
|
|
218
|
+
- An empty value (`null`, `undefined`, `""`) therefore renders nothing, unless an option explicitly declares that value.
|
|
219
|
+
|
|
67
220
|
## Limitations
|
|
68
|
-
|
|
69
|
-
- No support for grouped options or nested structures.
|
|
70
|
-
- No built-in formatting
|
|
71
|
-
-
|
|
221
|
+
|
|
222
|
+
- No support for grouped options or nested option structures.
|
|
223
|
+
- No built-in formatting of the label (wrap the component if needed).
|
|
224
|
+
- Multi-value data (an array of values) is not supported: the whole array is compared to each option value.
|
|
@@ -146,13 +146,22 @@ Use the `for` attribute to associate labels with form elements for accessibility
|
|
|
146
146
|
```
|
|
147
147
|
|
|
148
148
|
### Radio Buttons
|
|
149
|
+
|
|
150
|
+
Each radio must be checked only when the stored value is its own. `checked: ~.selectedSize` would check every radio as soon as a size is selected, so compare the value with an attribute transform:
|
|
151
|
+
|
|
149
152
|
```yaml
|
|
150
153
|
- type: input
|
|
151
154
|
attributes:
|
|
152
155
|
type: "radio"
|
|
153
156
|
name: "size"
|
|
154
157
|
value: "small"
|
|
155
|
-
|
|
158
|
+
attributeTransforms:
|
|
159
|
+
- what: setAttributeValue
|
|
160
|
+
name: checked
|
|
161
|
+
mode: replace
|
|
162
|
+
value: true
|
|
163
|
+
when: ~.selectedSize
|
|
164
|
+
is: "small"
|
|
156
165
|
actions:
|
|
157
166
|
- what: setData
|
|
158
167
|
on: change
|
|
@@ -164,7 +173,13 @@ Use the `for` attribute to associate labels with form elements for accessibility
|
|
|
164
173
|
type: "radio"
|
|
165
174
|
name: "size"
|
|
166
175
|
value: "large"
|
|
167
|
-
|
|
176
|
+
attributeTransforms:
|
|
177
|
+
- what: setAttributeValue
|
|
178
|
+
name: checked
|
|
179
|
+
mode: replace
|
|
180
|
+
value: true
|
|
181
|
+
when: ~.selectedSize
|
|
182
|
+
is: "large"
|
|
168
183
|
actions:
|
|
169
184
|
- what: setData
|
|
170
185
|
on: change
|
|
@@ -172,6 +187,8 @@ Use the `for` attribute to associate labels with form elements for accessibility
|
|
|
172
187
|
value: "large"
|
|
173
188
|
```
|
|
174
189
|
|
|
190
|
+
A checkbox or radio without a `checked` binding (attribute or attribute transform) is forced to unchecked and never shows a user's click. [CheckBoxField](../element/form/CheckBoxField.md) with `controlType: radio` handles all of this by itself.
|
|
191
|
+
|
|
175
192
|
## Advanced Patterns
|
|
176
193
|
|
|
177
194
|
### Form Validation with Conditional Actions
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Reaction: collectField
|
|
2
|
+
|
|
3
|
+
The `collectField` reaction writes the values of one field of every item of a collection, as an array. Typical use: a "select all" checkbox that writes the identifiers of the listed items.
|
|
4
|
+
|
|
5
|
+
## Properties
|
|
6
|
+
|
|
7
|
+
- `from` (string, required): The collection (template syntax), an array of objects.
|
|
8
|
+
- `field` (string, required): The name of the field to read in each item. It is evaluated.
|
|
9
|
+
- `path` (string, required): The location receiving the array (template syntax).
|
|
10
|
+
|
|
11
|
+
## Behavior
|
|
12
|
+
|
|
13
|
+
- The array of the `field` values is written at `path`, in the order of the collection.
|
|
14
|
+
- The items that are not objects, and the items whose field is `null`, `undefined` or an empty string, are skipped.
|
|
15
|
+
- A collection that is not an array writes an empty array.
|
|
16
|
+
- The collection is read from the complete data, even inside a `DataFilter`.
|
|
17
|
+
|
|
18
|
+
## Example
|
|
19
|
+
|
|
20
|
+
### Select all / deselect all
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
renderView:
|
|
24
|
+
- type: button
|
|
25
|
+
content: "Select all"
|
|
26
|
+
actions:
|
|
27
|
+
- what: collectField
|
|
28
|
+
on: click
|
|
29
|
+
from: ~~.results
|
|
30
|
+
field: nid
|
|
31
|
+
path: ~~.selection
|
|
32
|
+
- type: button
|
|
33
|
+
content: "Deselect all"
|
|
34
|
+
actions:
|
|
35
|
+
- what: setData
|
|
36
|
+
on: click
|
|
37
|
+
path: ~~.selection
|
|
38
|
+
value: []
|
|
39
|
+
|
|
40
|
+
data:
|
|
41
|
+
results:
|
|
42
|
+
- nid: 4
|
|
43
|
+
title: "First"
|
|
44
|
+
- nid: 9
|
|
45
|
+
title: "Second"
|
|
46
|
+
selection: []
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Limitations
|
|
50
|
+
|
|
51
|
+
- Only a direct field of the items is read (no nested path such as `author.id`).
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
renderView:
|
|
2
|
+
- type: Markdown
|
|
3
|
+
content: |
|
|
4
|
+
# Reaction: collectField
|
|
5
|
+
|
|
6
|
+
The `collectField` reaction writes the values of one field of every item of a collection, as an array. Typical use: a "select all" checkbox that writes the identifiers of the listed items.
|
|
7
|
+
|
|
8
|
+
## Properties
|
|
9
|
+
|
|
10
|
+
- type: DefinitionList
|
|
11
|
+
content:
|
|
12
|
+
- term:
|
|
13
|
+
code: from
|
|
14
|
+
after: "(string, required)"
|
|
15
|
+
details: "The collection (template syntax), an array of objects."
|
|
16
|
+
- term:
|
|
17
|
+
code: field
|
|
18
|
+
after: "(string, required)"
|
|
19
|
+
details: "The name of the field to read in each item. It is evaluated."
|
|
20
|
+
- term:
|
|
21
|
+
code: path
|
|
22
|
+
after: "(string, required)"
|
|
23
|
+
details: "The location receiving the array (template syntax)."
|
|
24
|
+
|
|
25
|
+
- type: Markdown
|
|
26
|
+
content: |
|
|
27
|
+
## Behavior
|
|
28
|
+
|
|
29
|
+
- The array of the `field` values is written at `path`, in the order of the collection.
|
|
30
|
+
- The items that are not objects, and the items whose field is `null`, `undefined` or an empty string, are skipped.
|
|
31
|
+
- A collection that is not an array writes an empty array.
|
|
32
|
+
- The collection is read from the complete data, even inside a `DataFilter`.
|
|
33
|
+
|
|
34
|
+
- type: RjBuildDescriber
|
|
35
|
+
title: "Select all / deselect all"
|
|
36
|
+
description: "collectField writes every nid of the results; setData empties the selection."
|
|
37
|
+
toDescribe:
|
|
38
|
+
renderView:
|
|
39
|
+
- type: button
|
|
40
|
+
attributes:
|
|
41
|
+
type: button
|
|
42
|
+
style:
|
|
43
|
+
marginRight: "0.5rem"
|
|
44
|
+
content: "Select all"
|
|
45
|
+
actions:
|
|
46
|
+
- what: collectField
|
|
47
|
+
on: click
|
|
48
|
+
from: ~~.results
|
|
49
|
+
field: nid
|
|
50
|
+
path: ~~.selection
|
|
51
|
+
- type: button
|
|
52
|
+
attributes:
|
|
53
|
+
type: button
|
|
54
|
+
content: "Deselect all"
|
|
55
|
+
actions:
|
|
56
|
+
- what: setData
|
|
57
|
+
on: click
|
|
58
|
+
path: ~~.selection
|
|
59
|
+
value: []
|
|
60
|
+
- type: div
|
|
61
|
+
content:
|
|
62
|
+
- type: strong
|
|
63
|
+
content: "Selection: "
|
|
64
|
+
- type: Join
|
|
65
|
+
content: ~~.selection
|
|
66
|
+
separator: ", "
|
|
67
|
+
data:
|
|
68
|
+
results:
|
|
69
|
+
- nid: 4
|
|
70
|
+
title: "First"
|
|
71
|
+
- nid: 9
|
|
72
|
+
title: "Second"
|
|
73
|
+
- nid: 15
|
|
74
|
+
title: "Third"
|
|
75
|
+
selection: []
|
|
76
|
+
|
|
77
|
+
- type: Markdown
|
|
78
|
+
content: |
|
|
79
|
+
## Limitations
|
|
80
|
+
|
|
81
|
+
- Only a direct field of the items is read (no nested path such as `author.id`).
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
- `requestKey` (string, optional): Identifier used to group requests that should cancel each other. When set, firing a new request with the same key aborts the previous one client-side (via AbortController). Different keys are independent. Bypasses the global lock automatically. See [Concurrency control](#concurrency-control--requestkey) below.
|
|
15
15
|
- `updateOnlyData` (boolean, optional): When true and `refreshAppOnResponse` is true, only updates the data section instead of replacing the entire RjBuild. Preserves templates and renderView. Default: false.
|
|
16
16
|
- `updateDataAtLocation` (string, optional): When `updateOnlyData` is true, specifies where to place the response data using template path syntax (e.g., "~~.userProfile", "~.config.settings"). If not specified, replaces the entire data object.
|
|
17
|
-
- `url` (string, required): The URL to call
|
|
17
|
+
- `url` (string or array, required): The URL to call: a string or a template reference (`~~.endpoint`), or an array of segments built like the `src` of `additionalDataSource` (literal strings, references evaluated in the current template context, `{segment, required}`, `{param, value, required}`). No request is sent when the URL is empty, or when a required segment is empty. See [Dynamic URLs with `src` as Array](../../getting-started/rjbuild-structure.md#dynamic-urls-with-src-as-array).
|
|
18
18
|
|
|
19
19
|
## Behavior
|
|
20
20
|
- Supports configurable HTTP methods (GET by default for backward compatibility)
|
|
@@ -232,6 +232,26 @@ actions:
|
|
|
232
232
|
refreshAppOnResponse: false
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
+
### URL built from the data
|
|
236
|
+
|
|
237
|
+
```yaml
|
|
238
|
+
- type: button
|
|
239
|
+
content: "Load"
|
|
240
|
+
actions:
|
|
241
|
+
- what: fetchData
|
|
242
|
+
on: click
|
|
243
|
+
url:
|
|
244
|
+
- "/api/items/"
|
|
245
|
+
- segment: ~.id
|
|
246
|
+
required: true
|
|
247
|
+
- param: display
|
|
248
|
+
value: ~~.display
|
|
249
|
+
updateOnlyData: true
|
|
250
|
+
updateDataAtLocation: ~~.details
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Inside a `Switch` item, `~.id` reads the item: each button loads its own item. Nothing is fetched when the item has no `id`.
|
|
254
|
+
|
|
235
255
|
## Limitations
|
|
236
256
|
- Only one request can be active at a time
|
|
237
257
|
- Response must be a valid rjbuild **only** if refreshAppOnResponse is true and updateOnlyData is false
|
|
@@ -52,10 +52,10 @@ renderView:
|
|
|
52
52
|
content: "When true and `refreshAppOnResponse` is true, only updates the data section instead of replacing the entire RjBuild. Preserves templates and renderView. Default: false"
|
|
53
53
|
- term:
|
|
54
54
|
code: url
|
|
55
|
-
after: "(string, required)"
|
|
55
|
+
after: "(string or array, required)"
|
|
56
56
|
details:
|
|
57
57
|
type: Markdown
|
|
58
|
-
content: "The URL to call
|
|
58
|
+
content: "The URL to call: a string or a template reference (`~~.endpoint`), or an array of segments built like the `src` of `additionalDataSource` (literal strings, references evaluated in the current template context, `{segment, required}`, `{param, value, required}`). No request is sent when the URL is empty, or when a required segment is empty."
|
|
59
59
|
|
|
60
60
|
- type: Markdown
|
|
61
61
|
content: |
|
|
@@ -11,6 +11,10 @@ Reactions in Reactive-JSON allow you to respond to user events and perform opera
|
|
|
11
11
|
- **[addData](./addData.md)**: Adds new data to the specified path
|
|
12
12
|
- **[removeData](./removeData.md)**: Removes data from the specified path
|
|
13
13
|
- **[moveData](./moveData.md)**: Moves data from one path to another
|
|
14
|
+
- **[toggleData](./toggleData.md)**: Adds a value to an array when absent, removes it when present
|
|
15
|
+
- **[collectField](./collectField.md)**: Writes the values of a field of every item of a collection as an array
|
|
16
|
+
- **[joinData](./joinData.md)**: Writes a string built from several parts (literals, references, segments)
|
|
17
|
+
- **[stringifyData](./stringifyData.md)**: Writes the JSON representation of a value
|
|
14
18
|
|
|
15
19
|
### Network Operations
|
|
16
20
|
- **[fetchData](./fetchData.md)**: Fetches data from a URL using GET requests
|
|
@@ -21,4 +25,5 @@ Reactions in Reactive-JSON allow you to respond to user events and perform opera
|
|
|
21
25
|
- **[redirectNow](./redirectNow.md)**: Performs an immediate redirect
|
|
22
26
|
- **[triggerEvent](./triggerEvent.md)**: Triggers a custom event
|
|
23
27
|
- **[postMessage](./postMessage.md)**: Sends a message to another window/frame
|
|
28
|
+
- **[printPage](./printPage.md)**: Opens the print dialog of the browser
|
|
24
29
|
|
|
@@ -14,6 +14,10 @@ renderView:
|
|
|
14
14
|
- **[addData](./addData)**: Adds new data to the specified path
|
|
15
15
|
- **[removeData](./removeData)**: Removes data from the specified path
|
|
16
16
|
- **[moveData](./moveData)**: Moves data from one path to another
|
|
17
|
+
- **[toggleData](./toggleData)**: Adds a value to an array when absent, removes it when present
|
|
18
|
+
- **[collectField](./collectField)**: Writes the values of a field of every item of a collection as an array
|
|
19
|
+
- **[joinData](./joinData)**: Writes a string built from several parts (literals, references, segments)
|
|
20
|
+
- **[stringifyData](./stringifyData)**: Writes the JSON representation of a value
|
|
17
21
|
|
|
18
22
|
### Network Operations
|
|
19
23
|
- **[fetchData](./fetchData)**: Fetches data from a URL using GET requests
|
|
@@ -24,3 +28,4 @@ renderView:
|
|
|
24
28
|
- **[redirectNow](./redirectNow)**: Performs an immediate redirect
|
|
25
29
|
- **[triggerEvent](./triggerEvent)**: Triggers a custom event
|
|
26
30
|
- **[postMessage](./postMessage)**: Sends a message to another window/frame
|
|
31
|
+
- **[printPage](./printPage)**: Opens the print dialog of the browser
|