Skip to content

Commit b4385d7

Browse files
committed
Improve label handling in MasterListComponent
The MasterListComponent did only show labels for object lists. Furthermore the options property in the uischema was mandatory. Also the property to use as label for objects had to be provided. The fix now handles primitives, a missing options property and in the case of a missing `labelRef` the first primitive property is used. If no primitive property is available the first property in the schema is used. Fix #1779
1 parent 96e2c41 commit b4385d7

File tree

4 files changed

+199
-4
lines changed

4 files changed

+199
-4
lines changed

packages/angular-material/src/other/master-detail/master.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
createDefaultValue,
3636
findUISchema,
3737
JsonFormsState,
38+
JsonSchema,
3839
mapDispatchToArrayControlProps,
3940
mapStateToArrayControlProps,
4041
RankedTester,
@@ -170,7 +171,7 @@ export class MasterListComponent extends JsonFormsArrayControl {
170171
const controlElement = uischema as ControlElement;
171172
this.propsPath = props.path;
172173
const detailUISchema =
173-
controlElement.options.detail ||
174+
controlElement.options?.detail ||
174175
findUISchema(
175176
props.uischemas,
176177
schema,
@@ -180,11 +181,12 @@ export class MasterListComponent extends JsonFormsArrayControl {
180181
);
181182

182183
const masterItems = (data || []).map((d: any, index: number) => {
183-
const labelRefInstancePath = removeSchemaKeywords(
184+
const labelRefInstancePath = controlElement.options?.labelRef && removeSchemaKeywords(
184185
controlElement.options.labelRef
185186
);
187+
const isPrimitive = d && typeof d !== 'object';
186188
const masterItem = {
187-
label: get(d, labelRefInstancePath),
189+
label: isPrimitive ? d.toString() : get(d, labelRefInstancePath ?? getFirstUsableProperty(schema)),
188190
data: d,
189191
path: `${path}.${index}`,
190192
schema,
@@ -247,6 +249,15 @@ export class MasterListComponent extends JsonFormsArrayControl {
247249
}
248250
}
249251

252+
const getFirstUsableProperty = (schema: JsonSchema): string => {
253+
const prop = Object.entries(schema?.properties).find(e => {
254+
if(e[1].type === 'object' || e[1].properties) return false;
255+
if(e[1].type === 'array' || e[1].items) return false;
256+
return true;
257+
});
258+
return prop ? prop[0] : Object.keys(schema?.properties)[0];
259+
}
260+
250261
export const masterDetailTester: RankedTester = rankWith(
251262
4,
252263
uiTypeIs('ListWithDetail')

packages/examples/src/1779.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
The MIT License
3+
4+
Copyright (c) 2017-2021 EclipseSource Munich
5+
https://github.com/eclipsesource/jsonforms
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in
15+
all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
THE SOFTWARE.
24+
*/
25+
import { registerExamples } from './register';
26+
27+
const data = {
28+
'an-array-of-strings': ['foo', 'bar', 'foobar']
29+
};
30+
const schema = {
31+
type: 'object',
32+
properties: {
33+
'an-array-of-strings': {
34+
type: 'array',
35+
items: {
36+
type: 'string'
37+
}
38+
}
39+
}
40+
};
41+
const uischema = {
42+
"type": "ListWithDetail",
43+
"scope": "#/properties/an-array-of-strings"
44+
};
45+
46+
registerExamples([
47+
{
48+
name: '1779',
49+
label: 'List With Detail primitive (string)',
50+
data,
51+
schema,
52+
uischema
53+
}
54+
]);
55+
56+
const data_number = {
57+
'an-array-of-numbers': [1, 2, 3]
58+
};
59+
const schema_number = {
60+
type: 'object',
61+
properties: {
62+
'an-array-of-numbers': {
63+
type: 'array',
64+
items: {
65+
type: 'number'
66+
}
67+
}
68+
}
69+
};
70+
const uischema_number = {
71+
"type": "ListWithDetail",
72+
"scope": "#/properties/an-array-of-numbers"
73+
};
74+
75+
registerExamples([
76+
{
77+
name: '1779',
78+
label: 'List With Detail primitive (string)',
79+
data: data_number,
80+
schema: schema_number,
81+
uischema: uischema_number
82+
}
83+
]);

packages/examples/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ import * as booleanToggle from './booleanToggle';
7474
import * as multiEnum from './multi-enum';
7575
import * as enumInArray from './enumInArray';
7676
import * as readonly from './readonly';
77+
import * as bug_1779 from './1779';
7778
export * from './register';
7879
export * from './example';
7980

@@ -132,5 +133,6 @@ export {
132133
booleanToggle,
133134
multiEnum,
134135
enumInArray,
135-
readonly
136+
readonly,
137+
bug_1779
136138
};

packages/examples/src/list-with-detail.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,95 @@ const uischema = {
195195
}
196196
};
197197

198+
const uischemaNoLabelRef = {
199+
type: 'ListWithDetail',
200+
scope: '#/properties/orders',
201+
options: {
202+
detail: {
203+
type: 'VerticalLayout',
204+
elements: [
205+
{
206+
type: 'HorizontalLayout',
207+
elements: [
208+
{
209+
type: 'Control',
210+
scope: '#/properties/title'
211+
},
212+
{
213+
type: 'Control',
214+
scope: '#/properties/processId'
215+
}
216+
]
217+
},
218+
{
219+
type: 'Group',
220+
label: 'Customer',
221+
elements: [
222+
{
223+
type: 'Control',
224+
label: 'ID',
225+
scope: '#/properties/customer/properties/id'
226+
},
227+
{
228+
type: 'Control',
229+
label: 'Name',
230+
scope: '#/properties/customer/properties/name'
231+
},
232+
{
233+
type: 'Control',
234+
label: 'Department',
235+
scope: '#/properties/customer/properties/department'
236+
}
237+
]
238+
},
239+
{
240+
type: 'VerticalLayout',
241+
elements: [
242+
{
243+
type: 'VerticalLayout',
244+
elements: [
245+
{
246+
type: 'HorizontalLayout',
247+
elements: [
248+
{
249+
type: 'Control',
250+
scope: '#/properties/ordered',
251+
options: {
252+
toggle: true
253+
}
254+
},
255+
{
256+
type: 'Control',
257+
scope: '#/properties/assignee'
258+
}
259+
]
260+
},
261+
{
262+
type: 'HorizontalLayout',
263+
elements: [
264+
{
265+
type: 'Control',
266+
scope: '#/properties/startDate'
267+
},
268+
{
269+
type: 'Control',
270+
scope: '#/properties/endDate'
271+
}
272+
]
273+
},
274+
{
275+
type: 'Control',
276+
scope: '#/properties/status'
277+
}
278+
]
279+
}
280+
]
281+
}
282+
]
283+
}
284+
}
285+
};
286+
198287
registerExamples([
199288
{
200289
name: 'list-with-detail',
@@ -204,3 +293,13 @@ registerExamples([
204293
uischema
205294
}
206295
]);
296+
297+
registerExamples([
298+
{
299+
name: 'list-with-detail-no-labelref',
300+
label: 'List With Detail (No Label Ref)',
301+
data,
302+
schema,
303+
uischema:uischemaNoLabelRef
304+
}
305+
]);

0 commit comments

Comments
 (0)