@vues3/flat-json-tree v0.6.20
A dead simple way to manipulate JSON tree objects
The core idea is to transform a JSON tree object into a flat array, allowing standard operations like find, findIndex, filter, map, and others.
A mandatory requirement for the algorithm is that each element in the JSON tree must have a field with a unique identifier.
To preserve the tree structure and enable manipulations, the following computed properties are added to each child object:
{
// Array of objects representing the path from root to current node
branch: Record < string, unknown > [];
// Index of the object in the sibling array
index: number;
// Next object in the sibling array
next: Record<string, unknown> | undefined;
// Parent object
parent: Record<string, unknown> | undefined;
// Previous object in the sibling array
prev: Record<string, unknown> | undefined;
// Array of sibling objects
siblings: Record < string, unknown > [];
}The transformation is performed using the useFlatJsonTree composable:
function useFlatJsonTree(
// The JSON tree object
tree: Record<string, unknown>[],
// Optional object to define alternative names for id, children, and computed properties
{
branch,
children,
id,
index,
next,
parent,
prev,
siblings,
}?: {
branch?: string | undefined;
children?: string | undefined;
id?: string | undefined;
index?: string | undefined;
next?: string | undefined;
parent?: string | undefined;
prev?: string | undefined;
siblings?: string | undefined;
},
);The composable returns an object with the following properties:
{
// Computed flat array of objects (access via .value)
leaves: ComputedRef<Record<string, unknown>[]>;
// Reactive array of objects
arrLeaves: Record<string, unknown>[];
// Reactive object with unique IDs as keys
objLeaves: {[id: string]: Record<string, unknown>;};
// Service function to add an empty object to the tree
add: (pId: string) => string | undefined;
// Service function to remove an object from the tree
remove: (pId: string) => string | undefined;
// Service function to move an object down by one position
down: (pId: string) => void;
// Service function to move an object left by one position
left: (pId: string) => string | undefined;
// Service function to move an object right by one position
right: (pId: string) => string | undefined;
// Service function to move an object up by one position
up: (pId: string) => void;
}Installation
npm i @vues3/flat-json-treeUsage
Assume we have a tree structure with elements like:
{ id: number, name: string, children: [] }Elements can contain arbitrary fields, but must have a unique identifier
Example using useFlatJsonTree composable
import useFlatJsonTree from "@vues3/flat-json-tree";
const tree = [
{
id: 1,
name: "root",
children: [
{
id: 2,
name: "1.2",
children: [
{ id: 5, name: "1.2.5" },
{ id: 6, name: "1.2.6" },
],
},
{ id: 3, name: "1.3" },
{
id: 4,
name: "1.4",
children: [
{ id: 7, name: "1.4.7" },
{ id: 8, name: "1.4.8" },
{ id: 9, name: "1.4.9" },
],
},
],
},
];
const { leaves, arrLeaves, objLeaves, add, down, left, remove, right, up } =
useFlatJsonTree(tree);Check the resulting flat array (using JSON.stringify to omit computed properties):
console.log(JSON.stringify(leaves.value));The result is a flat array containing all objects. Keep in mind that each object has computed properties added: branch, index, next, parent, prev, and siblings
[
{
"id": 1,
"name": "root",
"children": [
{
"id": 2,
"name": "1.2",
"children": [
{ "id": 5, "name": "1.2.5" },
{ "id": 6, "name": "1.2.6" }
]
},
{ "id": 3, "name": "1.3" },
{
"id": 4,
"name": "1.4",
"children": [
{ "id": 7, "name": "1.4.7" },
{ "id": 8, "name": "1.4.8" },
{ "id": 9, "name": "1.4.9" }
]
}
]
},
{
"id": 2,
"name": "1.2",
"children": [
{ "id": 5, "name": "1.2.5" },
{ "id": 6, "name": "1.2.6" }
]
},
{ "id": 5, "name": "1.2.5" },
{ "id": 6, "name": "1.2.6" },
{ "id": 3, "name": "1.3" },
{
"id": 4,
"name": "1.4",
"children": [
{ "id": 7, "name": "1.4.7" },
{ "id": 8, "name": "1.4.8" },
{ "id": 9, "name": "1.4.9" }
]
},
{ "id": 7, "name": "1.4.7" },
{ "id": 8, "name": "1.4.8" },
{ "id": 9, "name": "1.4.9" }
]Now let's try to find the object named "1.2.6":
console.log(JSON.stringify(arrLeaves.find(({ name }) => name === "1.2.6")));Output:
{ "id": 6, "name": "1.2.6" }If the ID is known, you can use objLeaves:
console.log(JSON.stringify(objLeaves[6]));Output:
{ "id": 6, "name": "1.2.6" }Now let's try using the computed properties. Suppose we need to find the parent element of the object named "1.2.6":
console.log(
JSON.stringify(arrLeaves.find(({ name }) => name === "1.2.6").parent),
);The result is the object named "1.2", which is the parent element of the object named "1.2.6":
{
"id": 2,
"name": "1.2",
"children": [
{ "id": 5, "name": "1.2.5" },
{ "id": 6, "name": "1.2.6" }
]
}Now let's add the object { id: 10, name: "1.2.10" } to the tree after the object named "1.2.6":
// Find the object named "1.2.6"
const curObject = arrLeaves.find(({ name }) => name === "1.2.6");
// Add the object { id: 10, name: "1.2.10" }
curObject.siblings.splice(curObject.index + 1, 0, { id: 10, name: "1.2.10" });
// Output the tree object passed to the useFlatJsonTree composable
console.log(JSON.stringify(tree));Output:
[
{
"id": 1,
"name": "root",
"children": [
{
"id": 2,
"name": "1.2",
"children": [
{ "id": 5, "name": "1.2.5" },
{ "id": 6, "name": "1.2.6" },
{ "id": 10, "name": "1.2.10" }
]
},
{ "id": 3, "name": "1.3" },
{
"id": 4,
"name": "1.4",
"children": [
{ "id": 7, "name": "1.4.7" },
{ "id": 8, "name": "1.4.8" },
{ "id": 9, "name": "1.4.9" }
]
}
]
}
]Finally, let's test the service function. Move the object named "1.2.6" to the position before "1.2.5":
// Find the object named "1.2.6"
const curObject = arrLeaves.find(({ name }) => name === "1.2.6");
// Use the service function up to move it
up(curObject.id);
// Output the tree object passed to the useFlatJsonTree composable
console.log(JSON.stringify(tree));As a result, the objects named "1.2.5" and "1.2.6" have swapped positions:
[
{
"id": 1,
"name": "root",
"children": [
{
"id": 2,
"name": "1.2",
"children": [
{ "id": 6, "name": "1.2.6" },
{ "id": 5, "name": "1.2.5" }
]
},
{ "id": 3, "name": "1.3" },
{
"id": 4,
"name": "1.4",
"children": [
{ "id": 7, "name": "1.4.7" },
{ "id": 8, "name": "1.4.8" },
{ "id": 9, "name": "1.4.9" }
]
}
]
}
]Made on the shores of the Baltic Sea
License: AGPL
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
8 months ago
9 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago