Skip to content

Commit e145b40

Browse files
authored
Merge pull request #2207 from plotly/cap-object-of
Component as props objectOf support.
2 parents b61cb82 + cef7bc7 commit e145b40

File tree

8 files changed

+406
-41
lines changed

8 files changed

+406
-41
lines changed

Diff for: @plotly/dash-test-components/src/components/ComponentAsProp.js

+35-2
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,36 @@ import PropTypes from 'prop-types';
33

44

55
const ComponentAsProp = (props) => {
6-
const { element, id, shapeEl, list_of_shapes, multi_components } = props;
6+
const {
7+
element,
8+
id,
9+
shapeEl,
10+
list_of_shapes,
11+
multi_components,
12+
dynamic,
13+
dynamic_list,
14+
dynamic_dict,
15+
dynamic_nested_list,
16+
} = props;
717
return (
818
<div id={id}>
919
{shapeEl && shapeEl.header}
1020
{element}
1121
{shapeEl && shapeEl.footer}
1222
{list_of_shapes && <ul>{list_of_shapes.map(e => <li key={e.value}>{e.label}</li>)}</ul> }
1323
{multi_components && <div>{multi_components.map(m => <div id={m.id} key={m.id}>{m.first} - {m.second}</div>)}</div>}
24+
{
25+
dynamic && <div>{Object.keys(dynamic).map(key => <div id={key} key={key}>{dynamic[key]}</div>)}</div>
26+
}
27+
{
28+
dynamic_dict && dynamic_dict.node && <div>{Object.keys(dynamic_dict.node).map(key => <div id={key} key={key}>{dynamic_dict.node[key]}</div>)}</div>
29+
}
30+
{
31+
dynamic_list && <div>{dynamic_list.map((obj, i) => Object.keys(obj).map(key => <div id={key} key={key}>{obj[key]}</div>))}</div>
32+
}
33+
{
34+
dynamic_nested_list && <div>{dynamic_nested_list.map((e => <>{Object.values(e.obj)}</>))}</div>
35+
}
1436
</div>
1537
)
1638
}
@@ -37,7 +59,18 @@ ComponentAsProp.propTypes = {
3759
first: PropTypes.node,
3860
second: PropTypes.node,
3961
})
40-
)
62+
),
63+
64+
dynamic: PropTypes.objectOf(PropTypes.node),
65+
66+
dynamic_list: PropTypes.arrayOf(PropTypes.objectOf(PropTypes.node)),
67+
68+
dynamic_dict: PropTypes.shape({
69+
node: PropTypes.objectOf(PropTypes.node),
70+
}),
71+
dynamic_nested_list: PropTypes.arrayOf(
72+
PropTypes.shape({ obj: PropTypes.objectOf(PropTypes.node)})
73+
),
4174
}
4275

4376
export default ComponentAsProp;

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
77
## Fixed
88

99
- [#2508](https://github.com/plotly/dash/pull/2508) Fix error message, when callback output has different length than spec
10+
- [#2207](https://github.com/plotly/dash/pull/2207) Fix object of components support.
1011

1112
## [2.9.3] - 2023-04-13
1213

Diff for: dash/dash-renderer/src/TreeContainer.js

+129-22
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
has,
1515
keys,
1616
map,
17+
mapObjIndexed,
1718
mergeRight,
1819
pick,
1920
pickBy,
@@ -252,24 +253,48 @@ class BaseTreeContainer extends Component {
252253

253254
for (let i = 0; i < childrenProps.length; i++) {
254255
const childrenProp = childrenProps[i];
256+
257+
const handleObject = (obj, opath) => {
258+
return mapObjIndexed(
259+
(node, k) => this.wrapChildrenProp(node, [...opath, k]),
260+
obj
261+
);
262+
};
263+
255264
if (childrenProp.includes('.')) {
256265
let path = childrenProp.split('.');
257266
let node;
258267
let nodeValue;
259268
if (childrenProp.includes('[]')) {
260269
let frontPath = [],
261270
backPath = [],
262-
found = false;
271+
found = false,
272+
hasObject = false;
263273
path.forEach(p => {
264274
if (!found) {
265275
if (p.includes('[]')) {
266276
found = true;
267-
frontPath.push(p.replace('[]', ''));
277+
if (p.includes('{}')) {
278+
hasObject = true;
279+
frontPath.push(
280+
p.replace('{}', '').replace('[]', '')
281+
);
282+
} else {
283+
frontPath.push(p.replace('[]', ''));
284+
}
285+
} else if (p.includes('{}')) {
286+
hasObject = true;
287+
frontPath.push(p.replace('{}', ''));
268288
} else {
269289
frontPath.push(p);
270290
}
271291
} else {
272-
backPath.push(p);
292+
if (p.includes('{}')) {
293+
hasObject = true;
294+
backPath.push(p.replace('{}', ''));
295+
} else {
296+
backPath.push(p);
297+
}
273298
}
274299
});
275300

@@ -281,38 +306,120 @@ class BaseTreeContainer extends Component {
281306
if (!firstNode) {
282307
continue;
283308
}
309+
284310
nodeValue = node.map((element, i) => {
285311
const elementPath = concat(
286312
frontPath,
287313
concat([i], backPath)
288314
);
289-
return assocPath(
290-
backPath,
291-
this.wrapChildrenProp(
315+
let listValue;
316+
if (hasObject) {
317+
if (backPath.length) {
318+
listValue = handleObject(
319+
rpath(backPath, element),
320+
elementPath
321+
);
322+
} else {
323+
listValue = handleObject(element, elementPath);
324+
}
325+
} else {
326+
listValue = this.wrapChildrenProp(
292327
rpath(backPath, element),
293328
elementPath
294-
),
295-
element
296-
);
329+
);
330+
}
331+
return assocPath(backPath, listValue, element);
297332
});
298333
path = frontPath;
299334
} else {
300-
node = rpath(path, props);
301-
if (node === undefined) {
302-
continue;
335+
if (childrenProp.includes('{}')) {
336+
// Only supports one level of nesting.
337+
const front = [];
338+
let dynamic = [];
339+
let hasBack = false;
340+
const backPath = [];
341+
342+
for (let j = 0; j < path.length; j++) {
343+
const cur = path[j];
344+
if (cur.includes('{}')) {
345+
dynamic = concat(front, [
346+
cur.replace('{}', '')
347+
]);
348+
if (j < path.length - 1) {
349+
hasBack = true;
350+
}
351+
} else {
352+
if (hasBack) {
353+
backPath.push(cur);
354+
} else {
355+
front.push(cur);
356+
}
357+
}
358+
}
359+
360+
const dynValue = rpath(dynamic, props);
361+
if (dynValue !== undefined) {
362+
nodeValue = mapObjIndexed(
363+
(d, k) =>
364+
this.wrapChildrenProp(
365+
hasBack ? rpath(backPath, d) : d,
366+
hasBack
367+
? concat(
368+
dynamic,
369+
concat([k], backPath)
370+
)
371+
: concat(dynamic, [k])
372+
),
373+
dynValue
374+
);
375+
path = dynamic;
376+
}
377+
} else {
378+
node = rpath(path, props);
379+
if (node === undefined) {
380+
continue;
381+
}
382+
nodeValue = this.wrapChildrenProp(node, path);
303383
}
304-
nodeValue = this.wrapChildrenProp(node, path);
305384
}
306385
props = assocPath(path, nodeValue, props);
307-
continue;
308-
}
309-
const node = props[childrenProp];
310-
if (node !== undefined) {
311-
props = assoc(
312-
childrenProp,
313-
this.wrapChildrenProp(node, [childrenProp]),
314-
props
315-
);
386+
} else {
387+
if (childrenProp.includes('{}')) {
388+
let opath = childrenProp.replace('{}', '');
389+
const isArray = childrenProp.includes('[]');
390+
if (isArray) {
391+
opath = opath.replace('[]', '');
392+
}
393+
const node = props[opath];
394+
395+
if (node !== undefined) {
396+
if (isArray) {
397+
for (let j = 0; j < node.length; j++) {
398+
const aPath = concat([opath], [j]);
399+
props = assocPath(
400+
aPath,
401+
handleObject(node[j], aPath),
402+
props
403+
);
404+
}
405+
} else {
406+
props = assoc(
407+
opath,
408+
handleObject(node, [opath]),
409+
props
410+
);
411+
}
412+
}
413+
} else {
414+
const node = props[childrenProp];
415+
if (node !== undefined) {
416+
props = assoc(
417+
childrenProp,
418+
this.wrapChildrenProp(node, [childrenProp]),
419+
props
420+
);
421+
}
422+
}
316423
}
317424
}
318425

Diff for: dash/dash-renderer/src/actions/callbacks.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ function fillVals(
163163
inputList.map(({id, property, path: path_}: any) => ({
164164
id,
165165
property,
166-
value: (path(path_, layout) as any).props[property]
166+
value: path([...path_, 'props', property], layout) as any
167167
})),
168168
specs[i],
169169
cb.anyVals,

0 commit comments

Comments
 (0)