Tengo un objeto anidado como este
let obj = { id: "XXX", children: [ { id: "YYY", children: [], path: ["XXX", "YYY"], type: "text" }, { id: "ZZZ", children: [], path: ["XXX", "ZZZ"], type: "button" } ], path: ["XXX"], type: "row" }; Necesito recorrer todos los elementos secundarios y actualizar la ruta agregando una matriz de cadenas que es const newPath = ["A", "B", "C"];
let newObj = cloneDeepWith(obj, (node) => { if (node.id) { node = { ...node, path: [...newPath, ...node.path] }; console.log("updated : ", node) } });Entonces, el resultado final del objeto de actualización debería ser este
let obj = { id: "XXX", children: [ { id: "YYY", children: [], path: ["A", "B", "C", "XXX", "YYY"], type: "text" }, { id: "ZZZ", children: [], path: ["A", "B", "C", "XXX", "ZZZ"], type: "button" } ], path: ["A", "B", "C", "XXX"], type: "row" };Estoy tratando de hacerlo con la función cloneDeepWith en lodash como esta
let updatedObj = cloneDeepWith(obj, (node) => { if (node.id) { node = { ...node, path: [...newPath, ...node.path] }; console.log("updated : ", node) } }); En cada console.log, imprime el nodo actualizado corregido (en este caso, 3 con el nodo principal), pero no regresa en updatedObj
Cómo puedo conseguir esto ?
No estoy seguro de cómo hacer esto es lodash , pero hacerlo en JS simple es bastante fácil. Su etiqueta de recursion es la clave..
p.ej.
let obj = { id: "XXX", children: [ { id: "YYY", children: [], path: ["XXX", "YYY"], type: "text" }, { id: "ZZZ", children: [], path: ["XXX", "ZZZ"], type: "button" } ], path: ["XXX"], type: "row" }; function addABC(obj) { if (obj.path) obj.path = ['A','B','C',...obj.path]; if (obj.children) for (const s of obj.children) addABC(s); } addABC(obj); console.log(obj);Podría hacer esto con Lodash usando el método cloneDeepWith pero en este caso también modificará los datos originales.
let obj = { id: "XXX", children: [{ id: "YYY", children: [], path: ["XXX", "YYY"], type: "text" }, { id: "ZZZ", children: [], path: ["XXX", "ZZZ"], type: "button" } ], path: ["XXX"], type: "row" }; const newPath = ["A", "B", "C"]; const clone = _.cloneDeepWith(obj, value => { if (_.isArray(value.path)) { value.path = [...newPath, ...value.path] } }) console.log(clone) <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>Un enfoque inmutable sin una biblioteca podría verse así:
const prependPaths = (prefix) => ({path, children, ...rest}) => ({ ...rest, path: [...prefix, ...path], children: children .map (prependPaths (prefix)) }) const obj = {id: "XXX", children: [{id: "YYY", children: [], path: ["XXX", "YYY"], type: "text"}, {id: "ZZZ", children: [], path: ["XXX", "ZZZ"], type: "button"}], path: ["XXX"], type: "row"} console .log (prependPaths (['A', 'B', 'C']) (obj)) .as-console-wrapper {max-height: 100% !important; top: 0} Esta es una recursividad directa, en la que map los elementos secundarios usando nuestra función, preconfigurada con el parámetro de prefix (aquí, ['A', 'B', 'C'] ).
Pero tenga en cuenta que los nodos de path de sus objetos contienen información redundante que podría derivarse de la jerarquía de identificadores, y si tiene un formulario sin procesar que no incluye estos nodos de path , aún podría lograr el mismo efecto con aproximadamente el mismo esfuerzo. :
const addPaths = (prefix = []) => ({id, children, ...rest}) => ({ id, ...rest, path: [...prefix, id], children: children .map (addPaths ([...prefix, id])) }) // No `path` nodes here. const obj2 = {id: "XXX", children: [{id: "YYY", children: [], type: "text"}, {id: "ZZZ", children: [], type: "button"}], type: "row"} // But the output includes the correct full paths. console .log (addPaths (['A', 'B', 'C']) (obj2)) .as-console-wrapper {max-height: 100% !important; top: 0} La principal diferencia es que las llamadas recursivas toman una versión actualizada del prefijo, agregando la id del objeto actual.