diff --git a/@plotly/dash-test-components/src/components/ComponentAsProp.js b/@plotly/dash-test-components/src/components/ComponentAsProp.js
index 867202b16c..52cf52d848 100644
--- a/@plotly/dash-test-components/src/components/ComponentAsProp.js
+++ b/@plotly/dash-test-components/src/components/ComponentAsProp.js
@@ -3,13 +3,14 @@ import PropTypes from 'prop-types';
const ComponentAsProp = (props) => {
- const { element, id, shapeEl, list_of_shapes } = props;
+ const { element, id, shapeEl, list_of_shapes, multi_components } = props;
return (
{shapeEl && shapeEl.header}
{element}
{shapeEl && shapeEl.footer}
{list_of_shapes &&
{list_of_shapes.map(e => - {e.label}
)}
}
+ {multi_components &&
{multi_components.map(m =>
{m.first} - {m.second}
)}
}
)
}
@@ -28,6 +29,14 @@ ComponentAsProp.propTypes = {
label: PropTypes.node,
value: PropTypes.number,
})
+ ),
+
+ multi_components: PropTypes.arrayOf(
+ PropTypes.exact({
+ id: PropTypes.string,
+ first: PropTypes.node,
+ second: PropTypes.node,
+ })
)
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e82dcd10b..41c01cd93a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,12 @@
All notable changes to `dash` will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/).
+## [UNRELEASED]
+
+### Fixed
+
+- [#2152](https://github.com/plotly/dash/pull/2152) Fix bug [#2128](https://github.com/plotly/dash/issues/2128) preventing rendering of multiple components inside a dictionary.
+
## [2.6.1] - 2022-08-01
### Fixed
diff --git a/dash/dash-renderer/src/TreeContainer.js b/dash/dash-renderer/src/TreeContainer.js
index 7d0fe968fd..04864c9db3 100644
--- a/dash/dash-renderer/src/TreeContainer.js
+++ b/dash/dash-renderer/src/TreeContainer.js
@@ -17,7 +17,6 @@ import {
mergeRight,
pick,
pickBy,
- pipe,
propOr,
path as rpath,
pathOr,
@@ -246,76 +245,73 @@ class BaseTreeContainer extends Component {
],
_dashprivate_config
);
- const props = pipe(
- dissoc('children'),
- ...childrenProps
- .map(childrenProp => {
- if (childrenProp.includes('.')) {
- let path = childrenProp.split('.');
- let node;
- let nodeValue;
- if (childrenProp.includes('[]')) {
- let frontPath = [],
- backPath = [],
- found = false;
- path.forEach(p => {
- if (!found) {
- if (p.includes('[]')) {
- found = true;
- frontPath.push(p.replace('[]', ''));
- } else {
- frontPath.push(p);
- }
- } else {
- backPath.push(p);
- }
- });
-
- node = rpath(frontPath, _dashprivate_layout.props);
- if (node === undefined) {
- return;
+ let props = dissoc('children', _dashprivate_layout.props);
+
+ for (let i = 0; i < childrenProps.length; i++) {
+ const childrenProp = childrenProps[i];
+ if (childrenProp.includes('.')) {
+ let path = childrenProp.split('.');
+ let node;
+ let nodeValue;
+ if (childrenProp.includes('[]')) {
+ let frontPath = [],
+ backPath = [],
+ found = false;
+ path.forEach(p => {
+ if (!found) {
+ if (p.includes('[]')) {
+ found = true;
+ frontPath.push(p.replace('[]', ''));
+ } else {
+ frontPath.push(p);
}
- if (!node.length) {
- return assocPath(frontPath, node);
- }
- const firstNode = rpath(backPath, node[0]);
- if (!firstNode) {
- return assocPath(frontPath, node);
- }
- nodeValue = node.map((element, i) => {
- const elementPath = concat(
- frontPath,
- concat([i], backPath)
- );
- return assocPath(
- backPath,
- this.wrapChildrenProp(
- rpath(backPath, element),
- elementPath
- ),
- element
- );
- });
- path = frontPath;
} else {
- node = rpath(path, _dashprivate_layout.props);
- if (node === undefined) {
- return;
- }
- nodeValue = this.wrapChildrenProp(node, path);
+ backPath.push(p);
}
- return assocPath(path, nodeValue);
+ });
+
+ node = rpath(frontPath, props);
+ if (node === undefined || !node.length) {
+ continue;
+ }
+ const firstNode = rpath(backPath, node[0]);
+ if (!firstNode) {
+ continue;
}
- const node = _dashprivate_layout.props[childrenProp];
- if (node !== undefined) {
- return assoc(
- childrenProp,
- this.wrapChildrenProp(node, [childrenProp])
+ nodeValue = node.map((element, i) => {
+ const elementPath = concat(
+ frontPath,
+ concat([i], backPath)
+ );
+ return assocPath(
+ backPath,
+ this.wrapChildrenProp(
+ rpath(backPath, element),
+ elementPath
+ ),
+ element
);
+ });
+ path = frontPath;
+ } else {
+ node = rpath(path, props);
+ if (node === undefined) {
+ continue;
}
- })
- .filter(e => e !== undefined)
- )(_dashprivate_layout.props);
+ 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
+ );
+ }
+ }
if (type(props.id) === 'Object') {
// Turn object ids (for wildcards) into unique strings.
diff --git a/tests/integration/renderer/test_component_as_prop.py b/tests/integration/renderer/test_component_as_prop.py
index 25a8c655a6..08b279fa94 100644
--- a/tests/integration/renderer/test_component_as_prop.py
+++ b/tests/integration/renderer/test_component_as_prop.py
@@ -1,7 +1,7 @@
from dash import Dash, Input, Output, callback_context
from dash_test_components import ComponentAsProp
-from dash.html import Button, Div
+from dash.html import Button, Div, Span
def test_rdcap001_component_as_prop(dash_duo):
@@ -90,6 +90,21 @@ def test_rdcap001_component_as_prop(dash_duo):
]
},
),
+ ComponentAsProp(
+ id="multi-component",
+ multi_components=[
+ {
+ "id": "multi",
+ "first": Span("first"),
+ "second": Span("second"),
+ },
+ {
+ "id": "multi2",
+ "first": Span("foo"),
+ "second": Span("bar"),
+ }
+ ],
+ ),
]
)
@@ -187,4 +202,7 @@ def updated_from_list(*_):
dash_duo.wait_for_text_to_equal("#first-in-shape", "one")
dash_duo.wait_for_text_to_equal("#second-in-shape", "two")
+ dash_duo.wait_for_text_to_equal("#multi", "first - second")
+ dash_duo.wait_for_text_to_equal("#multi2", "foo - bar")
+
assert dash_duo.get_logs() == []