Skip to content

Commit

Permalink
Merge pull request #2207 from plotly/cap-object-of
Browse files Browse the repository at this point in the history
Component as props objectOf support.
  • Loading branch information
T4rk1n authored Apr 26, 2023
2 parents b61cb82 + cef7bc7 commit e145b40
Show file tree
Hide file tree
Showing 8 changed files with 406 additions and 41 deletions.
37 changes: 35 additions & 2 deletions @plotly/dash-test-components/src/components/ComponentAsProp.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,36 @@ import PropTypes from 'prop-types';


const ComponentAsProp = (props) => {
const { element, id, shapeEl, list_of_shapes, multi_components } = props;
const {
element,
id,
shapeEl,
list_of_shapes,
multi_components,
dynamic,
dynamic_list,
dynamic_dict,
dynamic_nested_list,
} = props;
return (
<div id={id}>
{shapeEl && shapeEl.header}
{element}
{shapeEl && shapeEl.footer}
{list_of_shapes && <ul>{list_of_shapes.map(e => <li key={e.value}>{e.label}</li>)}</ul> }
{multi_components && <div>{multi_components.map(m => <div id={m.id} key={m.id}>{m.first} - {m.second}</div>)}</div>}
{
dynamic && <div>{Object.keys(dynamic).map(key => <div id={key} key={key}>{dynamic[key]}</div>)}</div>
}
{
dynamic_dict && dynamic_dict.node && <div>{Object.keys(dynamic_dict.node).map(key => <div id={key} key={key}>{dynamic_dict.node[key]}</div>)}</div>
}
{
dynamic_list && <div>{dynamic_list.map((obj, i) => Object.keys(obj).map(key => <div id={key} key={key}>{obj[key]}</div>))}</div>
}
{
dynamic_nested_list && <div>{dynamic_nested_list.map((e => <>{Object.values(e.obj)}</>))}</div>
}
</div>
)
}
Expand All @@ -37,7 +59,18 @@ ComponentAsProp.propTypes = {
first: PropTypes.node,
second: PropTypes.node,
})
)
),

dynamic: PropTypes.objectOf(PropTypes.node),

dynamic_list: PropTypes.arrayOf(PropTypes.objectOf(PropTypes.node)),

dynamic_dict: PropTypes.shape({
node: PropTypes.objectOf(PropTypes.node),
}),
dynamic_nested_list: PropTypes.arrayOf(
PropTypes.shape({ obj: PropTypes.objectOf(PropTypes.node)})
),
}

export default ComponentAsProp;
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
## Fixed

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

## [2.9.3] - 2023-04-13

Expand Down
151 changes: 129 additions & 22 deletions dash/dash-renderer/src/TreeContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
has,
keys,
map,
mapObjIndexed,
mergeRight,
pick,
pickBy,
Expand Down Expand Up @@ -252,24 +253,48 @@ class BaseTreeContainer extends Component {

for (let i = 0; i < childrenProps.length; i++) {
const childrenProp = childrenProps[i];

const handleObject = (obj, opath) => {
return mapObjIndexed(
(node, k) => this.wrapChildrenProp(node, [...opath, k]),
obj
);
};

if (childrenProp.includes('.')) {
let path = childrenProp.split('.');
let node;
let nodeValue;
if (childrenProp.includes('[]')) {
let frontPath = [],
backPath = [],
found = false;
found = false,
hasObject = false;
path.forEach(p => {
if (!found) {
if (p.includes('[]')) {
found = true;
frontPath.push(p.replace('[]', ''));
if (p.includes('{}')) {
hasObject = true;
frontPath.push(
p.replace('{}', '').replace('[]', '')
);
} else {
frontPath.push(p.replace('[]', ''));
}
} else if (p.includes('{}')) {
hasObject = true;
frontPath.push(p.replace('{}', ''));
} else {
frontPath.push(p);
}
} else {
backPath.push(p);
if (p.includes('{}')) {
hasObject = true;
backPath.push(p.replace('{}', ''));
} else {
backPath.push(p);
}
}
});

Expand All @@ -281,38 +306,120 @@ class BaseTreeContainer extends Component {
if (!firstNode) {
continue;
}

nodeValue = node.map((element, i) => {
const elementPath = concat(
frontPath,
concat([i], backPath)
);
return assocPath(
backPath,
this.wrapChildrenProp(
let listValue;
if (hasObject) {
if (backPath.length) {
listValue = handleObject(
rpath(backPath, element),
elementPath
);
} else {
listValue = handleObject(element, elementPath);
}
} else {
listValue = this.wrapChildrenProp(
rpath(backPath, element),
elementPath
),
element
);
);
}
return assocPath(backPath, listValue, element);
});
path = frontPath;
} else {
node = rpath(path, props);
if (node === undefined) {
continue;
if (childrenProp.includes('{}')) {
// Only supports one level of nesting.
const front = [];
let dynamic = [];
let hasBack = false;
const backPath = [];

for (let j = 0; j < path.length; j++) {
const cur = path[j];
if (cur.includes('{}')) {
dynamic = concat(front, [
cur.replace('{}', '')
]);
if (j < path.length - 1) {
hasBack = true;
}
} else {
if (hasBack) {
backPath.push(cur);
} else {
front.push(cur);
}
}
}

const dynValue = rpath(dynamic, props);
if (dynValue !== undefined) {
nodeValue = mapObjIndexed(
(d, k) =>
this.wrapChildrenProp(
hasBack ? rpath(backPath, d) : d,
hasBack
? concat(
dynamic,
concat([k], backPath)
)
: concat(dynamic, [k])
),
dynValue
);
path = dynamic;
}
} else {
node = rpath(path, props);
if (node === undefined) {
continue;
}
nodeValue = this.wrapChildrenProp(node, path);
}
nodeValue = this.wrapChildrenProp(node, path);
}
props = assocPath(path, nodeValue, props);
continue;
}
const node = props[childrenProp];
if (node !== undefined) {
props = assoc(
childrenProp,
this.wrapChildrenProp(node, [childrenProp]),
props
);
} else {
if (childrenProp.includes('{}')) {
let opath = childrenProp.replace('{}', '');
const isArray = childrenProp.includes('[]');
if (isArray) {
opath = opath.replace('[]', '');
}
const node = props[opath];

if (node !== undefined) {
if (isArray) {
for (let j = 0; j < node.length; j++) {
const aPath = concat([opath], [j]);
props = assocPath(
aPath,
handleObject(node[j], aPath),
props
);
}
} else {
props = assoc(
opath,
handleObject(node, [opath]),
props
);
}
}
} else {
const node = props[childrenProp];
if (node !== undefined) {
props = assoc(
childrenProp,
this.wrapChildrenProp(node, [childrenProp]),
props
);
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion dash/dash-renderer/src/actions/callbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ function fillVals(
inputList.map(({id, property, path: path_}: any) => ({
id,
property,
value: (path(path_, layout) as any).props[property]
value: path([...path_, 'props', property], layout) as any
})),
specs[i],
cb.anyVals,
Expand Down
Loading

0 comments on commit e145b40

Please sign in to comment.