Skip to content

Commit 0b9c040

Browse files
committed
support objectOf component type.
1 parent 2eb3ddb commit 0b9c040

File tree

4 files changed

+187
-37
lines changed

4 files changed

+187
-37
lines changed

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

+128-23
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import {
2020
propOr,
2121
path as rpath,
2222
pathOr,
23-
type
23+
type,
24+
toPairs
2425
} from 'ramda';
2526
import {notifyObservers, updateProps} from './actions';
2627
import isSimpleComponent from './isSimpleComponent';
@@ -249,24 +250,51 @@ class BaseTreeContainer extends Component {
249250

250251
for (let i = 0; i < childrenProps.length; i++) {
251252
const childrenProp = childrenProps[i];
253+
254+
const handleObject = (obj, opath) => {
255+
return keys(obj).reduce((acc, k) => {
256+
const node = acc[k];
257+
return {
258+
...acc,
259+
[k]: this.wrapChildrenProp(node, [...opath, k])
260+
};
261+
}, obj);
262+
};
263+
252264
if (childrenProp.includes('.')) {
253265
let path = childrenProp.split('.');
254266
let node;
255267
let nodeValue;
256268
if (childrenProp.includes('[]')) {
257269
let frontPath = [],
258270
backPath = [],
259-
found = false;
271+
found = false,
272+
hasObject = false;
260273
path.forEach(p => {
261274
if (!found) {
262275
if (p.includes('[]')) {
263276
found = true;
264-
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('{}', ''));
265288
} else {
266289
frontPath.push(p);
267290
}
268291
} else {
269-
backPath.push(p);
292+
if (p.includes('{}')) {
293+
hasObject = true;
294+
backPath.push(p.replace('{}', ''));
295+
} else {
296+
backPath.push(p);
297+
}
270298
}
271299
});
272300

@@ -278,38 +306,115 @@ class BaseTreeContainer extends Component {
278306
if (!firstNode) {
279307
continue;
280308
}
309+
281310
nodeValue = node.map((element, i) => {
282311
const elementPath = concat(
283312
frontPath,
284313
concat([i], backPath)
285314
);
286-
return assocPath(
287-
backPath,
288-
this.wrapChildrenProp(
315+
let listValue;
316+
if (hasObject) {
317+
listValue = handleObject(element, elementPath);
318+
} else {
319+
listValue = this.wrapChildrenProp(
289320
rpath(backPath, element),
290321
elementPath
291-
),
292-
element
293-
);
322+
);
323+
}
324+
return assocPath(backPath, listValue, element);
294325
});
295326
path = frontPath;
296327
} else {
297-
node = rpath(path, props);
298-
if (node === undefined) {
299-
continue;
328+
if (childrenProp.includes('{}')) {
329+
// Only supports one level of nesting.
330+
const front = [];
331+
let dynamic = [];
332+
let hasBack = false;
333+
const backPath = [];
334+
335+
for (let j = 0; j < path.length; j++) {
336+
const cur = path[j];
337+
if (cur.includes('{}')) {
338+
dynamic = concat(front, [
339+
cur.replace('{}', '')
340+
]);
341+
if (j < path.length - 1) {
342+
hasBack = true;
343+
}
344+
} else {
345+
if (hasBack) {
346+
backPath.push(cur);
347+
} else {
348+
front.push(cur);
349+
}
350+
}
351+
}
352+
353+
const dynValue = rpath(dynamic, props);
354+
if (dynValue !== undefined) {
355+
nodeValue = toPairs(dynValue).reduce(
356+
(acc, [k, d]) => ({
357+
...acc,
358+
[k]: this.wrapChildrenProp(
359+
hasBack ? rpath(backPath, d) : d,
360+
hasBack
361+
? concat(
362+
dynamic,
363+
concat([k], backPath)
364+
)
365+
: concat(dynamic, [k])
366+
)
367+
}),
368+
{}
369+
);
370+
path = dynamic;
371+
}
372+
} else {
373+
node = rpath(path, props);
374+
if (node === undefined) {
375+
continue;
376+
}
377+
nodeValue = this.wrapChildrenProp(node, path);
300378
}
301-
nodeValue = this.wrapChildrenProp(node, path);
302379
}
303380
props = assocPath(path, nodeValue, props);
304-
continue;
305-
}
306-
const node = props[childrenProp];
307-
if (node !== undefined) {
308-
props = assoc(
309-
childrenProp,
310-
this.wrapChildrenProp(node, [childrenProp]),
311-
props
312-
);
381+
} else {
382+
if (childrenProp.includes('{}')) {
383+
let opath = childrenProp.replace('{}', '');
384+
const isArray = childrenProp.includes('[]');
385+
if (isArray) {
386+
opath = opath.replace('[]', '');
387+
}
388+
const node = props[opath];
389+
390+
if (node !== undefined) {
391+
if (isArray) {
392+
for (let j = 0; j < node.length; j++) {
393+
const aPath = concat([opath], [j]);
394+
props = assocPath(
395+
aPath,
396+
handleObject(node[j], aPath),
397+
props
398+
);
399+
}
400+
} else {
401+
props = assoc(
402+
opath,
403+
handleObject(node, [opath]),
404+
props
405+
);
406+
}
407+
}
408+
} else {
409+
const node = props[childrenProp];
410+
if (node !== undefined) {
411+
props = assoc(
412+
childrenProp,
413+
this.wrapChildrenProp(node, [childrenProp]),
414+
props
415+
);
416+
}
417+
}
313418
}
314419
}
315420

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

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

Diff for: dash/dash-renderer/src/actions/utils.js

+57-12
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,64 @@ export const crawlLayout = (
6565
let [frontPath, backPath] = childrenProp
6666
.split('[]')
6767
.map(p => p.split('.').filter(e => e));
68-
const front = concat(['props'], frontPath);
69-
const basePath = concat(currentPath, front);
70-
crawlLayout(path(front, object), func, basePath, backPath);
68+
if (childrenProp.includes('{}')) {
69+
// TODO
70+
} else {
71+
const front = concat(['props'], frontPath);
72+
const basePath = concat(currentPath, front);
73+
crawlLayout(path(front, object), func, basePath, backPath);
74+
}
7175
} else {
72-
const newPath = concat(currentPath, [
73-
'props',
74-
...childrenProp.split('.')
75-
]);
76-
crawlLayout(
77-
path(['props', ...childrenProp.split('.')], object),
78-
func,
79-
newPath
80-
);
76+
if (childrenProp.includes('{}')) {
77+
const opath = childrenProp.split('.');
78+
const frontPath = [];
79+
const backPath = [];
80+
let found = false;
81+
82+
for (let i = 0; i < opath.length; i++) {
83+
const curPath = opath[i];
84+
if (!found && curPath.includes('{}')) {
85+
found = true;
86+
frontPath.push(curPath.replace('{}', ''));
87+
} else {
88+
if (found) {
89+
backPath.push(curPath);
90+
} else {
91+
frontPath.push(curPath);
92+
}
93+
}
94+
}
95+
const newPath = concat(currentPath, [
96+
'props',
97+
...frontPath
98+
]);
99+
100+
const oValue = path(['props', ...frontPath], object);
101+
if (oValue !== undefined) {
102+
Object.keys(oValue).forEach(key => {
103+
const value = oValue[key];
104+
if (backPath.length) {
105+
crawlLayout(
106+
path(backPath, value),
107+
func,
108+
concat(newPath, [key, ...backPath])
109+
);
110+
} else {
111+
crawlLayout(value, func, [...newPath, key]);
112+
}
113+
});
114+
}
115+
} else {
116+
const newPath = concat(currentPath, [
117+
'props',
118+
...childrenProp.split('.')
119+
]);
120+
crawlLayout(
121+
path(['props', ...childrenProp.split('.')], object),
122+
func,
123+
newPath
124+
);
125+
}
81126
}
82127
});
83128
}

Diff for: tests/integration/renderer/test_component_as_prop.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,6 @@ def on_click(n_clicks):
235235

236236
dash_duo.find_element("#click-dynamic").click()
237237

238-
dash_duo.wait_for_text_to_equal("#dynamic-output", "Clicked 1")
238+
dash_duo.wait_for_text_to_equal("#output-dynamic", "Clicked 1")
239239

240240
assert dash_duo.get_logs() == []

0 commit comments

Comments
 (0)