Reputation: 105
Given the following object:
const data = {
"root": {
"title": "Shapes",
"shapes": { ... },
"description": "All sorts of geometrical whizz"
}
}
I'd need to find a way to sort this object to have the keys with objects appear above the keys with strings, such as below:
const data = {
"root": {
"shapes": { ... },
"title": "Shapes",
"description": "All sorts of geometrical whizz"
}
}
What I have tried was the sort()
function:
const sorted = Object.values(root).sort((v) => typeof v === 'object' ? -1 : 1)
While this works to sort the values while keeping the root object pristine, the keys are lost in this new sorted
array...
[
{...},
"Shapes",
"All sorts of geometrical whizz"
]
...while it must be kept as an object as the keys are used by a recursive Tree Component, where sorting like this is moot:
<ng-template *ngFor="let key of Object.keys(data)">
<div *ngIf="typeof key === 'object'>
<button (click)="show(value)">
{{key}}
</button>
<this-template [data]="data[key]">
</div>
<div *ngIf="typeof key === 'string'>
<button (click)="show(value)">
{{key}}
</button>
</div>
</ng-template>
as the component will still render based on the structure of root
:
↓ root
|- title
|- > shapes
|- description
while the desired structure is this:
↓ root
|- > shapes
|- title
|- description
Thus, to define the problem in a single question;
How would I be able to sort an object by the type of the key's value, in order to render a recursive component to display items with objects before items with strings?
Upvotes: 2
Views: 1351
Reputation: 96
A bit shorter answer
let data = {
"root": {
"title": "Shapes",
"shapes": { key: 'value' },
"description": "All sorts of geometrical whizz"
}
};
/*
* looping through your `root` object's keys
* if the value of the key is object then assign the whole `data.root` object to a new object which starts with
* that key-value pair
*/
Object.keys(data.root).map(key => {
if ((typeof data.root[key]) === "object")
data.root = Object.assign({ [key]: data.root[key] }, data.root);
});
Upvotes: 1
Reputation: 14239
By using Object.entries
and a reduce you should be able to achieve the desired result:
const data = {
"root": {
"shapes": { /* ... */ },
"title": "Shapes",
"description": "All sorts of geometrical whizz"
}
}
const sorted = Object.entries(data.root)
.sort(([key, v]) => typeof v === 'object' ? -1 : 1)
.reduce((newObj, [key, v]) => ({ ...newObj, [key]: v }), {})
console.log(sorted)
Upvotes: 1
Reputation: 433
A not so elegant but fast solution would be
const data = {
"root": {
"title": "Shapes",
"shapes": { a: 'name' },
"description": "All sorts of geometrical whizz"
}
};
const object = {};
Object.values(data.root).forEach((a, i) => {
// console.log(a);
if (typeof(a) === 'object') {
object[Object.keys(data.root)[i]] = a;
}
});
Object.values(data.root).forEach((a, i) => {
// console.log(a);
if (!(typeof(a) === 'object')) {
object[Object.keys(data.root)[i]] = a;
}
});
console.log(object);
Upvotes: 1