Angular loop json display data - javascript

I want to make a loop to display data from my json but I am blocked on how to do it, I am quite a beginner and I want to know the best way to do it.
The question is how can I display the value 'name' knowing that there are keys with different names?
Thanks in advance.
example json
{
emptyKey: [],
mdnCars:
[
{
id: "1254",
name: "tesla"
}
],
mdiBrand : [],
mdnBrand:
[
{
id: "1254",
name: "renault"
}
]
}
ts.file
getAll() {
this.typeService.getAllType().subscribe(result => {
this.array = result
});
}

You can loop through the object to get the keys and the values.
for (const [key, value] of Object.entries(yourArray)) {
if(key !== 'emptyKey') {
for(const brand in value) {
console.log(brand);
}
}
}

You have got a typical problem to which I may have a clean and appropriate solution.
Now if you want to use *ngFor in Angular 2+ or ng-repeat in Angular, the best way would be to manipulate data as per your needs.
Taking into account your json,
{
emptyKey: [],
mdnCars:
[
{
id: "1254",
name: "tesla"
}
],
mdiBrand : [],
mdnBrand:
[
{
id: "1254",
name: "renault"
}
]
}
You only want to display the name from the JSON, write a helper function which can return you something like this
[
{
id: "1254",
name: "tesla"
},
{
id: "1254",
name: "renault"
}
]
After getting the above, perhaps then you can straightway use Angular's directive as per your needs.
I would have written a helper function but not sure of your JSON. Do let me know if you need it.
Happy Coding :)

const response = {
emptyKey: [],
mdnCars:
[
{
id: "1254",
name: "tesla"
}
],
mdiBrand : [],
mdnBrand:
[
{
id: "1254",
name: "renault"
}
]
};
const mdnCarsName = response.mdnCars.map(c => c.name);
// Guessing that you can also receive names in mdiBrand array
const mdiBrandsName = response.mdiBrand.map(b => b.name);
const mdnBrandsName = response.mdnBrand.map(b => b.name);
// A list of all cars and brands name, e.g: ['tesla', 'renault']
const allNames = mdnCarsName.concat(mdiBrandsName).concat(mdnBrandsName);
console.log(allNames)
EDIT:
You can also just use one loop, here i'm using reduce since there is already an answer using a for
const excludedKeys = ['emptyKey']
const response = {
emptyKey: [],
mdnCars:
[
{
id: "1254",
name: "tesla"
}
],
mdiBrand : [],
mdnBrand:
[
{
id: "1254",
name: "renault"
}
]
};
const list =
Object.entries(response).reduce((acc, [key, value]) => {
if (excludedKeys.includes(key))
return acc;
// You can get just the names with map(n => n.name), here i'm returning also the id's
acc.push(value.map(n => n));
return acc;
}, []).flat(1);
console.log(list)
EDIT 2
I leave here a simple testable example in angular:
app.component.ts
import { Component } from "#angular/core";
import { Observable } from "rxjs";
interface IMyResponse {
emptyKey: any[];
mdnCars: Item[];
mdiBrand : Item[];
mdnBrand: Item[];
}
interface Item {
id: string;
name: string;
}
function getObservable(): Observable<IMyResponse> {
return new Observable((observer) => observer.next({
emptyKey: [],
mdnCars:
[
{
id: "1254",
name: "tesla"
}
],
mdiBrand : [],
mdnBrand:
[
{
id: "1254",
name: "renault"
}
]
}));
}
#Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
data: Item[];
excludedKeys = ["emptyKey"];
ngOnInit(): void {
getObservable().subscribe(resp => this.data = this.transformResponse(resp));
}
transformResponse(response: IMyResponse): Item[] {
return Object.entries(response).reduce((acc, [key, value]) => {
if (this.excludedKeys.includes(key)) {
return acc;
}
// you can get just the names with map(n => n.name), here i'm returning also the id's
acc.push(value.map((n: Item) => n));
return acc;
}, []).flat(1);
}
}
app.component.html
<h2>Names</h2>
<ul>
<li *ngFor="let d of data">
<div>{{ d.id }} - {{ d.name }}</div>
</li>
</ul>

Related

Converting an array to an object of nested objects for a tree diagram in Javascript

i'm attempting to create a Tree Diagram with react-d3-js. It needs to be in a specific format. So i need to convert the initial data that i have to the format.
This is a diagram for a shop to see the distribution chain and who is allowed to make a purchase from specific nodes.
Initial Data:
store.name = 'Absolut Chocolat' //Main Parent
store.shopconditions: [
{
"role": "agent",
"condition": ["owner", "stokist"]
},
{
"role": "stokist",
"condition": ["owner", "master stokist"]
},
{
"role": "master stokist",
"condition": ["owner"]
}
]
// If role is agent, then they are allowed to buy from 'owner' and 'stokist'
Here's the hardcoded ideal output:
orgChart = {
name: 'Absolut Chocolat',
children: [
{ name: 'Agent' },
{
name: 'Stokist',
children: [
{
name: 'Agent',
},
],
},
{
name: 'Master Stokist',
children: [
{
name: 'Stokist',
children: [
{
name: 'Agent',
},
],
},
],
},
],
};
With a few for each loops, i've gotten to the first 2 layers of the intended output but i cannot find a way to get more than that.
Here is what i got so far:
Agent node is not under Master Stokist
Current code:
let chartData = { name: store.name, children: [] };
store.shopconditions.forEach((i) => {
i.condition.forEach((c) => {
if (c === 'owner') {
chartData.children.push({ name: i.role });
}
});
});
const chartDataParser = (data) => {
data.children.map((i) => {
for (const [k, v] of Object.entries(i)) {
store.shopconditions.forEach((c) => {
c.condition.forEach((o) => {
if (o === v) {
if (!i.children) {
i.children = [{ name: c.role }];
} else {
i.children.push({ name: c.role });
}
}
});
});
}
});
};
chartDataParser(chartData);
Current output:
{
name: 'Absolut Chocolat',
children: [
{ name: 'Agent' },
{
name: 'Stokist',
children: [
{
name: 'Agent',
},
],
},
{
name: 'Master Stokist',
children: [
{
name: 'Stokist',
// Missing children: Agent Node
},
],
},
],
};
What the tree diagram should look like:
As you can see under Master Stokist node, Agent is under Stokist
The Agent node is not reached under the stokist node in the right most chain. I need a fix to my current code so it can go to that extra layer. Thanks in advance. Looking forward to learn from your answers.
You can build an object that lists children by role and then use that to recursively build the nodes of the object. Possibly something like the following:
const store = {
name: 'Absolut Chocolat',
shopconditions: [
{ "role": "agent", "condition": ["owner", "stokist"], name: 'Agent' },
{ "role": "stokist", "condition": ["owner", "master stokist"], name: 'Stockist' },
{ "role": "master stokist", "condition": ["owner"], name: 'Master Stockist' },
]
};
const build_role_map = (store) => {
let role_map = Object.fromEntries(
store.shopconditions.map((v) => [v.role, { ...v, children: [] }])
);
role_map.owner = { "role": "owner", "condition": [], children: [], name: store.name };
store.shopconditions.forEach(
({ role, condition }) => {
condition.forEach((parent) => { role_map[parent].children.push(role) })
}
);
return role_map;
};
const build_node = (role_map, { name, children }) => {
let node = { name };
if(children.length > 0)
node.children = children.map((child) => build_node(role_map, role_map[child]));
return node;
};
const build_tree = (store) => {
const role_map = build_role_map(store);
return build_node(role_map, role_map.owner);
};
console.log(build_tree(store));

How to run a method using v-for in Vue.js?

I want to get the following output for the following data.
・3
・1
and sample data :
export const dummyData = [
{
id: "1",
name: "a",
sub: [
{
id: "1#1",
name: "b",
sub_sub: [
{ id: "1#1#1", name: "b-a" },
{ id: "1#1#2", name: "b-b" },
]
},
{
id: "1#2",
name: "c",
sub_sub: [
{ id: "1#2#1", name: "c-a" },
]
},
]
},
{
id: "2",
name: "d",
sub: [
{
id: "2#1",
name: "e",
sub_sub: [
{ id: "1#2#1", name: "e-a" },
]
}
]
},
]
I want to count how many elements of sub_sub are includes in object "a" and "d".
So, I made the following code.
<template>
<div>
<ul>
<li v-for="item in items" :key="item.i">{{rowSpanCalc(item.id)}}</li>
</ul>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import { dummyData } from '~/store/dummy'
#Component({})
export default class extends Vue {
items: any = []
created() {
this.items = dummyData
}
rowSpanCalc(item: any) {
const count = item.sub.reduce(
(total: any, curr: any) => total + curr.sub_sub.length,
0
)
return count;
}
}
</script>
I ran my code and got an error in console like
  
  item.sub.reduce is not a function
Could anyone please advise me how to fix this errors?
Methods in the template are used as events handler not for rendering, try to use that method inside a computed property then use that property for render your items :
#Component({})
export default class extends Vue {
items: any = []
created() {
this.items = dummyData
}
get customItems(){
return this.items.map(item=>({...item,count:this.rowSpanCalc(item.id)}))
}
rowSpanCalc(item: any) {
const count = item.sub.reduce(
(total: any, curr: any) => total + curr.sub_sub.length,
0
)
return count;
}
}
template :
...
<li v-for="item in customItems" :key="item.id">{{item.count}}</li>
...

Json formation in typescript (Angular 7)

I have a nested json as below.
{
card:[{
id:1;
details:[{id:1},{id:2}],
sheet:{
id:1
}
},{
id:2;
details:[{id:3},{id:4}],
sheet:{
id:1
}
}
]
}
I need to group details based on sheets as below.
{
sheet:{
id:1,
details:[{id:1},{id:2},{id:3},{id:4}]
}
}
How could I achieve this in typescript?
Went through NPM-groupBy but I don't think it really solves my problem.
Is there any other way to do this?
If I understand you correctly, this would be a good use case for the array reduce method, like:
const cards = [
{
id: 1,
details: [
{id:1},
{id:2}
],
sheet:{
id:1
}
},
{
id:2,
details: [
{id:3},
{id:4}
],
sheet:{
id:1
}
},
{
id:3,
details: [
{id:5},
{id:6}
],
sheet:{
id:2
}
}
];
const sheets = cards.reduce( (sheets: Array<any>, card: any) => {
const existingSheet = sheets.find(sheet => card.sheet.id === sheet.id);
if (existingSheet) {
existingSheet.details.concat(card.details);
} else {
sheets.push({id: card.sheet.id, details: card.details});
}
return sheets;
}, []
);
console.log(sheets);

Merge the object using typescript

In my angular application i am having the data as follows,
forEachArrayOne = [
{ id: 1, name: "userOne" },
{ id: 2, name: "userTwo" },
{ id: 3, name: "userThree" }
]
forEachArrayTwo = [
{ id: 1, name: "userFour" },
{ id: 2, name: "userFive" },
{ id: 3, name: "userSix" }
]
newObj: any = {};
ngOnInit() {
this.forEachArrayOne.forEach(element => {
this.newObj = { titleOne: "objectOne", dataOne: this.forEachArrayOne };
})
this.forEachArrayTwo.forEach(element => {
this.newObj = { titleTwo: "objectTwo", dataTwo: this.forEachArrayTwo };
})
console.log({ ...this.newObj, ...this.newObj });
}
In my real application, the above is the structure so kindly help me to achieve the expected result in the same way..
The working demo https://stackblitz.com/edit/angular-gyched which has the above structure.
Here console.log(this.newObj) gives the last object,
titleTwo: "ObjectTwo",
dataTwo:
[
{ id: 1, name: "userFour" },
{ id: 2, name: "userFive" },
{ id: 3, name: "userSix" }
]
but i want to combine both and need the result exactly like the below..
{
titleOne: "objectOne",
dataOne:
[
{ id: 1, name: "userOne" },
{ id: 2, name: "userTwo" },
{ id: 3, name: "userThree" }
],
titleTwo: "ObjectTwo",
dataTwo:
[
{ id: 1, name: "userFour" },
{ id: 2, name: "userFive" },
{ id: 3, name: "userSix" }
]
}
Kindly help me to achieve the above result.. If i am wrong in anywhere kindly correct with the working example please..
You're assigning both values to this.newObj, so it just overwrites the first object.
Also, there is no need for your loop. It doesn't add anything.
Instead, you can do:
this.newObjA = { titleOne: "objectOne", dataOne: this.forEachArrayOne };
this.newObjB = { titleTwo: "objectTwo", dataTwo: this.forEachArrayTwo };
console.log({ ...this.newObjA, ...this.newObjB });
**
EDIT **
Having spoken to you regarding your requirements, I can see a different solution.
Before calling componentData, you need to make sure you have the full data. To do this, we can use forkJoin to join the benchmark requests, and the project requests into one Observable. We can then subscribe to that Observable to get the results for both.
The code would look something like this:
createComponent() {
let benchmarks, projects;
let form = this.productBenchMarkingForm[0];
if (form.benchmarking && form.project) {
benchmarks = form.benchmarking.filter(x => x.optionsUrl)
.map(element => this.getOptions(element));
projects = form.project.filter(x => x.optionsUrl)
.map(element => this.getOptions(element));
forkJoin(
forkJoin(benchmarks), // Join all the benchmark requests into 1 Observable
forkJoin(projects) // Join all the project requests into 1 Observable
).subscribe(res => {
this.componentData({ component: NgiProductComponent, inputs: { config: AppConfig, injectData: { action: "add", titleProject: "project", dataProject: this.productBenchMarkingForm[0] } } });
})
}
}
getOptions(element) {
return this.appService.getRest(element.optionsUrl).pipe(
map((res: any) => {
this.dataForOptions = res.data;
element.options = res.data;
return element;
})
)
}
Here is an example in Stackblitz that logs the data to the console

Sort item list by earliest collection dateTime in angular2

I'm new to angular2 and I'm trying to sort out my food order list by collection time datestamp coming from the database.
let say the order object is below and in my template I want to sort it with earliest collectiontime in the example below it would be id: 2454
var awaitingPicking = [
{
"id": "2452",
"OrderLineGroups": [
{
"CollectionDetails": {
"CollectionFrom": "2017-03-21T11:00:00.317"
}
}
]
},
{
"id": "2454",
"OrderLineGroups": [
{
"CollectionDetails": {
"CollectionFrom": "2017-03-21T11:00:00.317"
}
}
]
}
]
Image shows how my list is being rendered in my HTML and it puts id: 2454 at the bottom when it should be before id: 2452.
Edit --
this.awaitingPicking.push(element); // these holds all order objects
this.awaitingPicking.map(e => {
this.getCollectionFrom = e.CollectionFrom = e.OrderLineGroups[0].CollectionDetails.CollectionFrom
return e
})
Template --
<div *ngFor="let prepare of awaitingPicking | orderBy: '+getCollectionFrom'" id="prepareOrder"> </div>
How can I sort the list with earliest collectionFrom?
sample image
the solution uses a custom filter that only goes one level deep, so your data must also be only 1 level deep:
https://plnkr.co/edit/rCGc2IZECuPiL3QqNnlJ?p=preview (updated)
changes:
app.ts
//...
#Component({
selector: 'my-app',
providers: [],
pipes: [DatePipe, ArraySortPipe],
template: `
<ul>
<li *ngFor="#item of sortableArray | arraySort:'+CollectionFrom'">{{item.id}} {{item.CollectionFrom}}</li>
</ul>
`,
directives: []
})
//...
export class App {
inputArray: Array<any> = [
{
"id": "2452",
"OrderLineGroups": [
{
"CollectionDetails": {
"CollectionFrom": "2017-03-21T11:40:00.317"
}
}
]
},
{
"id": "2454",
"OrderLineGroups": [
{
"CollectionDetails": {
"CollectionFrom": "2017-03-21T11:00:00.317"
}
}
]
}
]
sortableArray: Array<any> = this.inputArray.map(e => {
e.CollectionFrom = e.OrderLineGroups[0].CollectionDetails.CollectionFrom
return e
})
constructor() {}
}
//...

Categories

Resources