Angular - Populate the HTML page with the JSON data - javascript

I have the following JSON data but would like to implement the HTML page such that it shows the parent as the header and all the children under the same parent under the content and then follow by the second parent as the header and all the children under the second parent under the content. How would I be able to do so? An example would be the following:
Sample 1
Product 1 - Test Product 1
Product 2 - Test Product 2
Sample 2
Product 1 - Test Product 1
"sampleList": [
{
"parent": "Sample 1",
"children": [
{
"product": "Product 1",
"name": "Test Product 1"
}
]
},
{
"parent": "Sample 1",
"children": [
{
"product": "Product 2",
"name": "Test Product 2"
}
]
},
{
"parent": "Sample 2",
"children": [
{
"product": "Product 1",
"name": "Test Product 1"
}
]
}
]

With Array.reduce() to perform group by parent and concatenate array.
Create a new array from result 1 with each object element has parent and children property.
let grouped = this.sampleList.reduce((groups, current) => {
groups[current.parent] = groups[current.parent] || [];
groups[current.parent].push(...current.children);
return groups;
}, Object.create(null));
this.groupedSampleList = Object.keys(grouped).map((key) => ({
parent: key,
children: grouped[key],
}));
If you use es2017, you can work with Object.entries() as:
this.groupedSampleList = Object.entries(grouped).map((value) => ({
parent: value[0],
children: value[1],
}));
<div *ngFor="let parent of groupedSampleList">
<strong>{{ parent.parent }}</strong>
<div *ngFor="let child of parent.children">
{{ child.product }} - {{ child.name }}
</div>
</div>
Demo on StackBlitz

The JSON data structure provided contains duplicate keys which is not ideal. Also, parents with the same value have children stored in separate locations. If the format could be improved such that each parent and child are separate items in the list, it can be easily performed iteratively using a ngFor, which allows you to iterate through data. Providing the JSON key will display the needed child elements. I have included an example below. https://angular.io/api/common/NgForOf
Reformatted Data:
sampleList":
[
{
"parent": "Sample 1",
"children": [
{
"product": "Product 1",
"name": "Test Product 1",
},
{
"product": "Product 1",
"name": "Test Product 1",
}],
},
{
"parent": "Sample 2",
"children": [
{
"product": "Product 1",
"name": "Test Product 1",
}]
}
]
<li *ngFor="let item of sampleList; index as I;">
<h3> {{item.parent}} </h3>
<li *ngFor="let item2 of sampleList[I].children;">
<div> {{item2.product}} - {{item2.name}}</div>
</li>
</li>

Related

Best way to iterate hierarchical JSON/JS data

I'm hitting some performance issues with various implementations of this...
Essentially, I have a dataset of around 1500 objects in the below form: -
{
"Id": "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3",
"ParentId": null,
"Name": "Main Location",
"Children": [
{
"Id": "3cb93d59-613c-4797-8858-bc3f31f6baa0",
"ParentId": "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3",
"Name": "Site A",
"Children": [
{
"Id": "a1fec942-b425-4307-905d-9e2a6f8730b3",
"ParentId": "3cb93d59-613c-4797-8858-bc3f31f6baa0",
"Name": "Location A1",
"Children": [
{
"Id": "5538e976-db1c-49c2-8cab-70aafc1e4e70",
"ParentId": "a1fec942-b425-4307-905d-9e2a6f8730b3",
"Name": "Location A1 a",
"Children": []
},
{
"Id": "6f5a536f-4b4f-4a10-b7ba-657d772d0588",
"ParentId": "a1fec942-b425-4307-905d-9e2a6f8730b3",
"Name": "Location A1 b",
"Children": []
}
]
}
]
},
{
"Id": "319db987-994d-45d5-9023-8f21b8a589cb",
"ParentId": "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3",
"Name": "Site B",
"Children": [
{
"Id": "f0c1f222-4118-4c07-b7be-30ff70fada03",
"ParentId": "319db987-994d-45d5-9023-8f21b8a589cb",
"Name": "Location B1",
"Children": [
{
"Id": "fe33043d-4cf2-498e-aa80-04848e109acb",
"ParentId": "f0c1f222-4118-4c07-b7be-30ff70fada03",
"Name": "Location B1 b",
"Children": []
},
{
"Id": "d92ae7d5-bc44-4e94-be75-0cda5a254664",
"ParentId": "f0c1f222-4118-4c07-b7be-30ff70fada03",
"Name": "Location B1 b",
"Children": [
{
"Id": "0a89ee4a-3b18-4772-baa3-fc0682d7053f",
"ParentId": "d92ae7d5-bc44-4e94-be75-0cda5a254664",
"Name": "Location B1 b Special Site...",
"Children": []
}
]
}
]
}
]
}
]
}
]
It has an unknown depth, as in the children can continue to exist on each object...
Firstly, I would love to know what would be the fastest way to search this to find one of the objects given an Id (GUID). I have tried all sorts, I've experimented with flattening it out and using ES6 .find() (instead of filter for singular results...), I've written a custom iterator that essentially starts at the top and works it's way through the children until a match is found... These solutions work, I'm just wondering if there's a trick I'm missing..?
One area this slows down is if I want to then climb the tree from the found object, so if I use the .find() approach, and I want to know all of it's parents, I then need to also find() each parent based on the ParentId...
Secondly, now this perhaps is a bit of a unique use case, but essentially, I populate a customised React Treeview in JS with this data, and in the treeview, each item has a checkbox... Once the user checks the box, I add the object Id attribute to a 'selected' array to track what has been selected and what hasn't...
Where this gets complicated, is I don't want to then select all of the parent items above it, but instead need to know their ids so I can store them in a 'partially selected' array to illustrate on the Treeview that they haven't been selected, but a child of it somewhere has... (I conditionally change the styling of the checkbox depending if it's a Selected or 'Partially Selected' checkbox...
This is the key area where the slowdown occurs, because the User might check only 3 or 4 checkboxes mid way down the tree, which will also check all of their children, and this these 'partially selected' ids need to be found for each 'fully' checked item in the tree...
Make sense? :-S
I'm wondering basically, is there some super duper fast way that people usually use when working with things like this or is the nature of it slow and that's that because I simply need to check each route individually..?
Thanks!
You could build a hash map and have a fast access to the wanted objects.
const
buildHashMap = (r, o) => {
r[o.Id] = o;
return o.Children
? o.Children.reduce(buildHashMap, r)
: r;
},
data = [{ Id: "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3", ParentId: null, Name: "Main Location", Children: [{ Id: "3cb93d59-613c-4797-8858-bc3f31f6baa0", ParentId: "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3", Name: "Site A", Children: [{ Id: "a1fec942-b425-4307-905d-9e2a6f8730b3", ParentId: "3cb93d59-613c-4797-8858-bc3f31f6baa0", Name: "Location A1", Children: [{ Id: "5538e976-db1c-49c2-8cab-70aafc1e4e70", ParentId: "a1fec942-b425-4307-905d-9e2a6f8730b3", Name: "Location A1 a", Children: [] }, { Id: "6f5a536f-4b4f-4a10-b7ba-657d772d0588", ParentId: "a1fec942-b425-4307-905d-9e2a6f8730b3", Name: "Location A1 b", Children: [] }] }] }, { Id: "319db987-994d-45d5-9023-8f21b8a589cb", ParentId: "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3", Name: "Site B", Children: [{ Id: "f0c1f222-4118-4c07-b7be-30ff70fada03", ParentId: "319db987-994d-45d5-9023-8f21b8a589cb", Name: "Location B1", Children: [{ Id: "fe33043d-4cf2-498e-aa80-04848e109acb", ParentId: "f0c1f222-4118-4c07-b7be-30ff70fada03", Name: "Location B1 b", Children: [] }, { Id: "d92ae7d5-bc44-4e94-be75-0cda5a254664", ParentId: "f0c1f222-4118-4c07-b7be-30ff70fada03", Name: "Location B1 b", Children: [{ Id: "0a89ee4a-3b18-4772-baa3-fc0682d7053f", ParentId: "d92ae7d5-bc44-4e94-be75-0cda5a254664", Name: "Location B1 b Special Site...", Children: [] }] }] }] }] }],
hashmap = data.reduce(buildHashMap, {});
console.log(hashmap);
Had you tried a custom recursive function?
function findId(data, id) {
const { Id, Children } = data;
if(id === Id) return data;
if(! Children || Children.length === 0) return null;
for(let i = 0; i < Children.length; ++i) {
const ret = findId(Children[i], id);
if(ret) return ret;
}
return null;
}
Hope this helps.

Parse an array of nested objects in a particular way

I have an array of objects that can have other arrays of object as children (it can have a complex hierarchy): if an object has a children prop — it's a group, if it doesn't — it's an item:
var myData = [
{
"name": "item 1"
},
{
"name": "group 1",
"children": [
{
"name": "item in a group 1"
}]
},
{
"name": "group 2",
"children": [
{
"name": "group 1 in a group 2",
"children": [
{
"name": "item in a nested group 1"
},
{
"name": "deeply nested group",
"children": [
{
"name": "deep item"
}]
},]
},
{
"name": "group 2 in a group 2",
"children": [
{
"name": "item in a nested group 2"
}]
}]
}]
and I want to parse it to have a flat object that would have all groups as props and items as arrays, each prop would also include items from grandchildren groups.
Currently with the code below I'm able to flatten the array and have groups as props and items as arrays for each object:
{
"root": [
"item 1"
],
"group 1": [
"item in a group 1"
],
"group 2": [],
"group 1 in a group 2": [
"item in a nested group 1"
],
"deeply nested group": [
"deep item"
],
"group 2 in a group 2": [
"item in a nested group 2"
]
}
However I 'm struggling with adding grandchildren. Here's the desired output:
{
"root": [
"item 1"
],
"group 1": [
"item in a group 1"
],
"group 2": [
"item in a nested group 1", // includes items of child groups
"item in a nested group 2",
"deep item"
],
"group 1 in a group 2": [
"item in a nested group 1",
"deep item" // includes item of a child group
],
"deeply nested group": [
"deep item"
],
"group 2 in a group 2": [
"item in a nested group 2"
]
}
here's my code I'm using (I can only use older version of pure JS so no ES6, NPM; can use polyfill though)
var myItems = {
'root': []
}
var i;
for (i = 0; i < myData.length; i++)
{
parseItems(myData[i], 'root')
}
function parseItems(data, groupName)
{
var key, i;
for (key in data)
{
if (!data.hasOwnProperty(key))
continue;
else if (data.hasOwnProperty('children'))
{
groupName = data['name']
if (myItems[groupName] == undefined) myItems[groupName] = []
for (i = 0; i < data[key].length; i++)
{
parseItems(data[key][i], groupName);
}
}
else
{
myItems[groupName].push(data['name']);
}
}
}
And I don't understand how can I make a version of this code (or something better probably?) that'd fill parent groups with grandchildren items.
Ancient version.
function flat(array, parents, target) {
var i, j;
parents = parents || [];
target = target || { root: [] };
for (i = 0; i < array.length; i++) {
if (array[i].children) {
flat(array[i].children, parents.concat(array[i].name), target);
continue;
}
if (parents.length) {
for (j = 0; j < parents.length; j++) {
if (!target[parents[j]]) target[parents[j]] = [];
target[parents[j]].push(array[i].name);
}
} else {
target.root.push(array[i].name);
}
}
return target;
}
var data = [{ name: "item 1" }, { name: "group 1", children: [{ name: "item in a group 1" }] }, { name: "group 2", children: [{ name: "group 1 in a group 2", children: [{ name: "item in a nested group 1" }, { name: "deeply nested group", children: [{ name: "deep item" }] }] }, { name: "group 2 in a group 2", children: [{ name: "item in a nested group 2" }] }] }],
result = flat(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

how to send iterated json data to html Id's

My html and json with jquery is below. please someone help me to do this in javascript function.
Is there any other way without using clone function?
with pure javascript can we do this any other way to display json content in HTML id's
$(function () {
// Fake JSON result - array of values
json = [{
fields: {
imagem: "Image 1",
nome_produto: "Name 1",
descricao: "Description 1",
preco_produto: "product 1"
}
}, {
fields: {
imagem: "Image 2",
nome_produto: "Name 2",
descricao: "Description 2",
preco_produto: "product 2"
}
}, {
fields: {
imagem: "Image 3",
nome_produto: "Name 3",
descricao: "Description 3",
preco_produto: "product 3"
}
}];
// take a copy of an existing one as a template
$.each(json, function (i, items) {
var clone = $('.conteudo:first').clone();
clone.find('.foto').text(items.fields['imagem']);
clone.find('.inf:eq(0)').text(items.fields['nome_produto']);
clone.find('.inf:eq(1)').text(items.fields['descricao']);
clone.find('.inf:eq(2)').text(items.fields['preco_produto']);
$('section').append(clone);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section>
<div class="conteudo">
<div class="foto">FOTO</div>
<div class="inf">TITULO</div>
<div class="inf">DESCRICAO</div>
<div class="inf">PRECO</div>
</div>
</section>
My html and json with jquery is below. please someone help me to do this in javascript function.
Is there any other way without using clone function?
with pure javascript can we do this any other way to display json content in HTML id's
result should be json data like below
Image 1
Name 1
Description 1
product 1
Image 2
Name 2
Description 2
product 2
Image 3
Name 3
Description 3
product
You can build the html as a string using concatenation:
To add a unique id to each row use the index i variable provided by the foreach loop
$(function () {
// Fake JSON result - array of values
json = [{
fields: {
imagem: "Image 1",
nome_produto: "Name 1",
descricao: "Description 1",
preco_produto: "product 1"
}
}, {
fields: {
imagem: "Image 2",
nome_produto: "Name 2",
descricao: "Description 2",
preco_produto: "product 2"
}
}, {
fields: {
imagem: "Image 3",
nome_produto: "Name 3",
descricao: "Description 3",
preco_produto: "product 3"
}
}];
// take a copy of an existing one as a template
$.each(json, function (i, items) {
var clone = '<div class="conteudo" id="conteudo'+i+'"><div class="foto">'+items.fields['imagem']+'</div><div class="inf">'+items.fields['nome_produto']+'</div><div class="inf">'+items.fields['descricao']+'</div><div class="inf">'+items.fields['preco_produto']+'</div></div>'
$('section').append(clone);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section>
</section>

Getting Specific data from Nested Json which is having multiple Parent Children

Am trying to filter out some specific data's from Nested JSON which is having multiple Parent Children . Here is my json ,
[{
"id": "111111",
"name": "Parent",
"steps": [{
"id": "22222",
"name": "Child",
"steps": [{
"id": "333333",
"name": "Child -Child",
"steps": [{
"id": "444444",
"name": "Child - Child - Child",
"steps": [{
"id": "5555",
"name": "Child - Child - Child - Child"
}, {
"id": "522e9327-0747-4080-b6e2-d57e726b5b26",
"name": "Child - Child - Child - Child 2"
}],
}],
}],
}],
}]
What am trying to do here is i have to get some specific data's which are inside this nested json . For Ex : i need output like ["parent","Child","Child-Child"...etc ] . So i used map function using java script but the output was different like this one ["ParentChildChildChild"] (With No spaces) .If output's are String only mean's i can put "\n" and separate them but sometimes they are in Numbers so problem will occur's . Here is my Code which i tried ,
var myReturnedValues = mainSteps.map(x => [
x.steps.map(y => y.name +
y.steps.map(z => z.name +
z.steps.map(a => a.name + a.steps.map(b => b.name))
)
)
]);
Can someone help/clarify Me .
To achieve this most effectively you need To achieve this most effectively you need To achieve this most effectively you need to use recursion use recursion use recursion.
Using this pattern means that the array will always be filled no matter how many levels of nested object you have. Try this:
var data = [{
"id": "111111",
"name": "Parent",
"steps": [{
"id": "22222",
"name": "Child",
"steps": [{
"id": "333333",
"name": "Child -Child",
"steps": [{
"id": "444444",
"name": "Child - Child - Child",
"steps": [{
"id": "5555",
"name": "Child - Child - Child - Child"
}, {
"id": "522e9327-0747-4080-b6e2-d57e726b5b26",
"name": "Child - Child - Child - Child 2"
}],
}],
}],
}],
}]
var names = [];
function getNames(arr) {
for (var i = 0; i < arr.length; i++) {
names.push(arr[i].name);
if (arr[i].steps && arr[i].steps.length)
getNames(arr[i].steps);
}
}
getNames(data);
console.log(names);
You can achieve this using the javascript map function & recursion
var jsonArray = [{
"id": "111111",
"name": "Parent",
"steps": [{
"id": "22222",
"name": "Child",
"steps": [{
"id": "333333",
"name": "Child -Child",
"steps": [{
"id": "444444",
"name": "Child - Child - Child",
"steps": [{
"id": "5555",
"name": "Child - Child - Child - Child"
}, {
"id": "522e9327-0747-4080-b6e2-d57e726b5b26",
"name": "Child - Child - Child - Child 2"
}],
}],
}],
}],
}]
var namesArray = [];
var recur = function(obj) {
namesArray.push(obj.name);
if(obj.steps) {
obj.steps.map(recur);
}
}
jsonArray.map(recur);
console.log(namesArray);
You can also try
function getObjectKeyValues(obj, objKey) {
var result = [];
JSON.stringify(obj, function(key, value) {
if (key === objKey) {
result.push(value)
}
return;
});
return result;
}
Check:
MDN JSON.stringify()

How to get two different array objects together

Here i attached my json .
"mainSteps": [
{
"id": "9b3b64b4-d8a5-46d5-b464-066dc5c45dc3",
"name": "Main Step 1",
"steps": [
{
"name": "sub step 1.1"
},
{
"name": "sub step 1.2"
}
]
},
{
"name": "Main step 2"
"steps": [
{
"name": "sub step 2.1"
},
{
"name": "sub step 2.2"
}
],
},
{
"name": "Main Step 3",
"steps": [
{
"name": "sub step 3.1"
},
{
"name": "sub step 3.2"
}
],
}
]
am looking for the output like --> [Main Step 1, sub step 1.1 , sub step 1.2] ,[Main Step 2, sub step 2.1 , sub step 2.2] , [Main Step 3, sub step 3.1 , sub step 3.2] . I spend the whole day for this output but am getting output like [[Main Step 1,Main Step 2,Main Step 3,sub step 1.1,sub step 1.2....] Like that am getting different format's but am unable to get the actual output as i mentioned about , Can someone clarify me .
var dataProcess = {
parentProcess:[],
subProcess:[]
};
var steps = mainData.steps; // Steps Having the Full json data
var proc = [];
$scope.getSteps = function(steps) {
for (var i=0;i< steps.length;i++) {
dataProcess.parentProcess.push(steps[i].name);
for(var j=i;j<steps[i].steps.length;j++){
dataProcess.subProcess.push(steps[i].steps[j].name);
}
}
This is one of the way i tried ,
If you need ES5 syntax:
var details = mainSteps.map(function(step) {
return [ step.name ].concat((step.steps || []).map(function(substep){
return substep.name;
})
});
ES6 syntax:
var details = mainSteps.map(step =< [step.name].concat((step.steps || []).map(sub => sub.name));
If you need more recursion than one layer deep, you can use a function as the top level mapper, that calls itself.
May be you can do like this;
var mainSteps = [
{
"id": "9b3b64b4-d8a5-46d5-b464-066dc5c45dc3",
"name": "Main Step 1",
"steps": [
{
"name": "sub step 1.1"
},
{
"name": "sub step 1.2"
}
]
},
{
"name": "Main step 2",
"steps": [
{
"name": "sub step 2.1"
},
{
"name": "sub step 2.2"
}
],
},
{
"name": "Main Step 3",
"steps": [
{
"name": "sub step 3.1"
},
{
"name": "sub step 3.2"
}
],
}
],
mapped = mainSteps.map(e => [e.name, e.steps[0].name, e.steps[1].name]);
console.log(mapped);
this way, it's working with various length of array and sub arrays :
var results = mainSteps.map(x => [x.name].concat(x.steps.map(y => y.name)));
Simple solution using Array.map and Array.concat functions:
// supposing "obj" is your initial object
var dataProcess = obj.mainSteps.map(function (o) {
return [o.name].concat(o.steps.map(function(v){ return v.name; }));
});
console.log(JSON.stringify(dataProcess, 0, 4));
The output:
[
[
"Main Step 1",
"sub step 1.1",
"sub step 1.2"
],
[
"Main step 2",
"sub step 2.1",
"sub step 2.2"
],
[
"Main Step 3",
"sub step 3.1",
"sub step 3.2"
]
]
DEMO link

Categories