Angular looping values individually - json

In my component.ts I have something like this
testOptions: SelectItem[] = Object.keys(TestEnum).map(a => {
return { label: this.translate.instant('TestEnum.' + a), value: a };
});
test.enum.ts:
export enum TestEnum {
A = 'A',
B = 'B',
C = 'C',
}
"translate" uses a json file in my case en.json:
"TestEnum": {
"test1": "Test 1",
"test2": "Test 2",
"test3": "Test 3",
my component.html looks like this:
<ng-template #tBody let-row="row">
<td class="iconLinkColumn">
<span *ngIf="!isRowMenuDisabled(row)" class="newton-more" [title]="'common.options' | translate"
style="padding-bottom: 8px;" (click)="toggleRowMenu($event, rowMenu, row)"></span>
</td>
<td>
<span *ngFor="let f of avrFlagOptions">
{{ f.label}}
</span>
</td>
When I start my angular app I am getting displaying all of my json names in each row of my table. How is it possible to loop the values individually, so that in row one appears Test 1 and in row two appears Test 2?

Very sure testOptions is an KeyValue Array and I cannot see a ngFor in your code.
This I believe will do the trick.
Answer:
<si-newton-section>
<cc-scrollable-table>
<ng-template #tBody let-row="row">
<td class="iconLinkColumn" *ngFor="let option of testOptions | keyvalue">
<span *ngIf="!isRowMenuDisabled(row)" class="newton-more" [title]="'common.options' | translate"
style="padding-bottom: 8px;" (click)="toggleRowMenu($event, rowMenu, row)"></span>
<td>{{option.value}}</td>
</ng-template>
</cc-scrollable-table>
</si-newton-section>

Related

Angular - How to Iterate through an object that some of the keys are undefined

So I have objectA and objectB
objectA {
0: {name: 'M', date: '2021-10-24'}
1: {name: 'T', date: '2021-10-25'}
2: {name: 'W', date: '2021-10-26'}
3: {name: 'T', date: '2021-10-27'}
4: {name: 'F', date: '2021-10-28'}
5: {name: 'S', date: '2021-10-29'}
6: {name: 'S', date: '2021-10-30'}
}
objectB {
2021-10-29: [{…}]
2021-10-30: [{…}, {…}]
}
objectA holds all the days in the current week and objectB holds all the appointments(building an appointments app) in the current week, so objectB can have an appointment every day, having the dates of the appointments as keys or it can have only one, two or even 0 date keys, depending if there are appointments or not. In the above example there is only one appointment on the 29'th and two on the 30'th.
My problem is that I want to iterate through objectB in the HTML(to get some appointment data) by getting the keys(the date strings) from objectA. I get this Error and the iteration stops because the key I'm trying to access does not exist.
ERROR:
ERROR TypeError: Cannot read properties of undefined (reading '2021-10-24')
This is my HTML:
<tbody>
<tr>
<td *ngFor="let day of objectA">
<div *ngFor="let app in objectB[day.date]">
<span *ngIf="app">{{ app.startTime | date : 'HH:mm' }}</span>
</div>
</td>
</tr>
</tbody>
So I guess my question is how do I iterate through objectB without knowing all its keys, or how to make the for loop ignore the undefined and just continue to iterate.
Thanks!
Solution 1
You need KeyValuePipe to iterate for the object in order to get keys and values.
<td *ngFor="let kv of objectA | keyvalue;">
<div *ngFor="let app of objectB[kv.value.date]">
<span *ngIf="app">{{ app.startTime | date: 'HH:mm' }}</span>
</div>
</td>
Sample Solution 1 on StackBlitz
Solution 2
Convert objectA to array with Object.keys().
aList = Object.keys(this.objectA).map((x: any) => this.objectA[x]);
<td *ngFor="let day of aList;">
<div *ngFor="let app of objectB[day.date]">
<span *ngIf="app">{{ app.startTime | date: 'HH:mm' }}</span>
</div>
</td>
Sample Solution 2 on StackBlitz
<tbody>
<tr>
<td *ngFor="let day of objectA">
<ng-container *ngIf="objectB[day.date]">
<div *ngFor="let app in objectB[day.date]">
<span *ngIf="app">{{ app.startTime | date : 'HH:mm' }}</span>
</div>
</ng-container>
</td>
</tr>
</tbody>
Just add an if condition and check if that key exist in ObjectB then loop thought it

How to iterate over values of Map values

I would like to fill of this cells, this is initiall view of my app:
-> during app works for each rider rider's score will be fulfilled in such a way:
I have a .ts file where I put values of rider score (it's a map -> key is heat number, value - score of particular rider) (if it will be both string or number depends on further configuration)
export const guests = {
1: new Racer(9, 'Name_1', new Map([['1', 1], ['4', 2], ['7', 4]])),
2: new Racer(10, 'Name_2', new Map([['1', 3], ['3', 4]])),
3: new Racer(11, 'Name_3', new Map([['2', 3], ['6', 2]])),
4: new Racer(12, 'Name_4', new Map([['6', 3], ['10', 3], ['13', 2]]))
};
I would like to get all values of map values in html, however I'm not able to iterate over values of this map.
Further info: There should be all the time displayed all cells (it is designed that there should be exactly the same at the beginning
We don't know how entries for each racer there will be (probably for each rider this will be different)
<table>
<tbody>
<tr *ngFor="let racer of team; let index = index">
<td>{{racer.number}}</td>
<td>{{racer.name}}</td>
<td *ngIf="racer.places">{{racer.places.values().next().value}}</td>
<td *ngIf="racer.places">{{racer.places.values().next().value}}</td>
<td *ngIf="racer.places">{racer.places.values().next().value}}</td>
<td *ngIf="racer.places">{racer.places.values().next().value}}</td>
<td *ngIf="racer.places">{racer.places.values().next().value}}</td>
</tr>
</tbody>
</table>
expected output
instead of only first entry there should be all values from Map
working repo:
https://stackblitz.com/edit/angular-iterate-over-map-values
The way you are initializing the map doesn't create a map after all. Make the following change to guests:
// now it actually contains key-value pairs
const guests = {
1: new Racer(9, "Name_1", { "1": 1, "4": 2, "7": 4 }),
2: new Racer(10, "Name_2", { "1": 3, "3": 4 }),
3: new Racer(11, "Name_3", { "2": 3, "6": 2 }),
4: new Racer(12, "Name_4", { "6": 3, "10": 3, "13": 2 }),
};
now create a new property in the team object called remaining, this holds an array which contains the extra number of columns that are needed for each row. It is dynamically created for each racer.
team = Object.values(guests).map(racer => {
return {
...racer,
remaining: new Array(5 - Object.values(racer.places).length)
}
});
and on the template, iterate over this newly created array for the remaining <td> that should be empty:
<table>
<tbody>
<tr *ngFor="let racer of team">
<td>{{racer.number}}</td>
<td>{{racer.name}}</td>
<td *ngFor="let heat of racer.places | keyvalue">
{{ heat.value }}
</td>
<td *ngFor="let rem of racer.remaining" style="width: 10px;">
</td>
</tr>
</tbody>
</table>
This is some awful data structure to work with.
Simply loop through the range that you need and check for each cell if the data exists with .has() method. Show the data in a ternary expression with .get() method if it exists, or null if it's missing.
Here is the HTML code that should work with your data structure:
<table>
<thead>
<tr>
<td>No.</td>
<td>Racer</td>
<td *ngFor="let p of [1,2,3,4,5]">{{p}}</td>
<td>Sum</td>
<td *ngFor="let p of [6,7]">{{p}}</td>
<td>Sum</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let racer of team; let index = index">
<td>{{racer.number}}</td>
<td>{{racer.name}}</td>
<td *ngFor="let p of [1,2,3,4,5]">{{racer.places.has(""+p) ? racer.places.get(""+p) : null}}</td>
<td>TODO: Sum</td>
<td *ngFor="let p of [6,7]">{{racer.places.has(""+p) ? racer.places.get(""+p) : null}}</td>
<td>TODO: Sum</td>
</tr>
</tbody>
</table>
Unless you are planning to expand the Racer class, I suggest you switch it to an interface and simply use JSON data structure with Objects instead of a Map

How to extract keys from JSON where its value is true

I have below JSON, from this I want to extract Skills where it is true.
[
{
"_id":"5de9f351baca28556c6a4b71",
"Name":"Harsha",
"Age":20,
"Gender":"M",
"Skills":{
"Java":"",
"Mule":true,
"Angular":""
}
},
{
"_id":"5de9f358baca28556c6a4b72",
"Name":"Anji",
"Age":21,
"Gender":"M",
"Skills":{
"Java":"",
"Mule":true,
"Angular":true
}
},
{
"_id":"5dea110297c2b65298b136e4",
"Name":"Abhi",
"Age":25,
"Gender":"M",
"Skills":{
"Java":"",
"Mule":true,
"Angular":""
}
}
]
I am able to print rest of the data using below code
<table *ngIf="formTemplate">
<tr>
<th *ngFor="let header of questionTitleArray" >{{header}}</th>
</tr>
<tr *ngFor="let data of surveyDataFromDB">
<ng-container *ngFor="let head of questionTitleArray">
<td>{{data[head]}}</td>
</ng-container>
</tr>
</table>
(Here JSON is "surveyDataFromDB")
Below is the output I am getting
Name Age Gender Skills
Harsha 20 M [object Object]
Anji 21 M [object Object]
Abhi 25 M [object Object]
I want Skills which are true in place of [object Object]. Please help.
You can first map your object to only have the truthy ones. You can use lodash pickBy.
mappedSurveyDataFromDB = this.surveyDataFromDB.map(
entry => ({...entry, Skills: _pickBy(entry.Skills, Boolean)}),
);
After change the template like this:
<table>
<tr>
<th *ngFor="let header of questionTitleArray">{{ header }}</th>
</tr>
<tr *ngFor="let data of mappedSurveyDataFromDB">
<ng-container *ngFor="let head of questionTitleArray">
<td *ngIf="head !== 'Skills'">{{ data[head] }}</td>
<td *ngIf="head === 'Skills'">
<ng-container *ngFor="let entry of (data[head] | keyvalue); let last = last">
{{ entry.key }}
<ng-container *ngIf="!last">, </ng-container>
</ng-container>
</td>
</ng-container>
</tr>
</table>
Stackblitz: https://stackblitz.com/edit/angular-ga7lqg
you can try like this
<table *ngIf="formTemplate">
<tr>
<th *ngFor="let header of questionTitleArray" >{{header}}</th>
</tr>
<tr *ngFor="let data of surveyDataFromDB">
<ng-container *ngFor="let head of questionTitleArray">
// here we are iterating a loop with keyvalue pipe bcs "Skills" is object
<span *ngIf="typeOf(data[head]) === 'object' else elsePart">
<td *ngFor="let j of data[head] | keyvalue">
{{j.key}} {{j.value}}
<td>
</span>
<ng-template #elsePart>
{{data[head]}}
<ng-template>
</ng-container>
</tr>
</table>
<table>
<tr>
<th *ngFor="let header of questionTitleArray">{{ header }} </th>
</tr>
<tr *ngFor="let data of surveyDataFromDB">
<ng-container *ngFor="let head of questionTitleArray">
<span *ngIf="checkType(data[head]) else elsePart">
<span *ngFor="let j of data[head] | keyvalue">
<td *ngIf="j.value==true">
{{j.key}}
</td>
</span>
</span>
<ng-template #elsePart>
<td>{{data[head]}}</td>
</ng-template>
</ng-container>
</tr>
</table>
in ts:
checkType(Ob:any)
{
if(typeof (Ob) === 'object')
return true;
else
return false;
}
You can process before render on ui, and create a comma seprated string of skill key on the basics of its value
let list=[{"_id":"5de9f351baca28556c6a4b71","Name":"Harsha","Age":20,"Gender":"M","Skills":{"Java":"","Mule":true,"Angular":""}},{"_id":"5de9f358baca28556c6a4b72","Name":"Anji","Age":21,"Gender":"M","Skills":{"Java":"","Mule":true,"Angular":true}},{"_id":"5dea110297c2b65298b136e4","Name":"Abhi","Age":25,"Gender":"M","Skills":{"Java":"","Mule":true,"Angular":""}}];
let result = list.map((o) => { return {...o, 'Skills': Object.entries(o.Skills).reduce((acc, i) => acc+= i[1] ? `${i[0]},`: '' , '').slice(0, -1) } });
console.log(result)
Or You can checkout this demo may this helps you
In template you can use KeyValuePipe to iterate on object i.e skills and show skill key only when its value is not falsy
<ng-container *ngFor="let entry of (data[head] | keyvalue); let last = last">
{{ entry.value ? entry.key: '' }}
<ng-container *ngIf="!last && entry.value">,</ng-container>
</ng-container>
Okey so you want to extract all the skills that are true and place them in a new object. From what I know there is not built in function to do this, however I wrote some code to to exactly this
var skills = {
Java: "",
Mule: true,
Angular: "",
Cpp: true,
Maja: false,
NodeJs: true
}
let keys = Object.keys(skills);
let trueSkills = {};
keys.forEach(keyValue => {
if (skills[keyValue] == true)
trueSkills[keyValue] = true;
});
console.log(trueSkills); // These are all the true skills
I hope this helps
Dealing with object keys based on their values can be complex in an Angular template. You could try to transform "Skills" into an array of strings. For example you could do it like this:
get formattedData() {
// this.data would be your json object
return this.data.map(i => ({...i, Skills: Object.keys(i.Skills).filter(j => i.Skills[j] === true)}))
}
This loops through every entry and transforms the skills object into an array with the skills.
This would return:
[
{
"_id":"5de9f351baca28556c6a4b71",
"Name":"Harsha",
"Age":20,
"Gender":"M",
"Skills":[
"Mule"
]
},
{
"_id":"5de9f358baca28556c6a4b72",
"Name":"Anji",
"Age":21,
"Gender":"M",
"Skills":[
"Mule",
"Angular"
]
},
{
"_id":"5dea110297c2b65298b136e4",
"Name":"Abhi",
"Age":25,
"Gender":"M",
"Skills":[
"Mule"
]
}
]
A minimal working example: Stackblitz
I would strongly advise against this method though, if you have a lot of entries as it would take a long time.
Skills attribute in your data is an Object. ngFor can only be used with Iteratable. Therefore first you should convert Skills to an Array. It can be done as below.
dataForView: any[];
prepareDataForView() {
this.dataForView = [...this.surveyDataFromDB];
this.dataForView.map(item => {
item.Skills = Object.keys(item.Skills).map(key => {
if (item.Skills[key]) {
return key;
}
});
});
}
And then you bind new array to View.
Find working Stackblitz Demo.

How to iterate a JSON array in typescript in HTML?

I have a snippets of JSON array as shown below:
[{
"auction_number": "015",
"email": "pete#abc.com",
"first_name": "Peter",
"last_name": "Dan",
"table": 0,
"id": "015"
},
{
"auction_number": "024",
"email": "dan#gog.com",
"first_name": "Dan",
"last_name": "Fain",
"table": 0,
"id": "024"
}
]
Typescript Code:
The typescript (ts) for the above JSON array is shown below. Here attendees is an array object.
attendees: Attendee[];
constructor(public authService: AuthService) {
const str = localStorage.getItem("attendees");
if(str) {
this.attendees = JSON.parse(str);
console.log(str);
}
}
HTML Code:
The HTML code which I have used in order to iterate everything from the JSON array (in the typescript code) is shown below. For some reasons, it is not able to iterate attendees in the HTML.
<tr *ngFor="let row of attendees">
<td class="left">{{ attendees.first_name }} {{ attendees.last_name }}</td>
<td class="number1">250</td>
<td class="table1">{{attendees.table}}</td>
<td class="right-bill">Bill</td>
</tr>
Problem Statement:
I am wondering what changes I should make in the HTML code above so that I am successfully able to iterate attendees array. I tried using ngfor directive but somehow it didn't work.
You should reference fields in each row as row.first_name because you set each attendee as let row of attendees. The variable you defined is row.
You are accessing the parent loop again, you should access only the elements of row
<tr *ngFor="let row of attendees">
<td class="left">{{ row .first_name }} {{ row .last_name }}</td>
<td class="number1">250</td>
<td class="table1">{{attendees.table}}</td>
<td class="right-bill">Bill</td>
</tr>

Unable to iterate *ngFor loop with array of column in table

I have table like this which i want to iterate
Heating Diesel Benzin Fracht
43.10 87.15 108.00
43.35 87.40 108.25
43.80 87.80 108.60 2394.00
----- ----- ----- ----
Here is json data which i want to insert into my table and here first object is one column, second object is second column like that i need to insert 4 columns. i don't understand how to iterate this with *ngFor loop. please excuse if any thing wrong in my question.
[
{
"s4": "43,10",
"s5": "43,35",
"s6": "43,80",
"s7": "43,90",
"s8": "44,10",
"s15": "64,25",
"s9": "44,55",
"s10": "43,20",
"s11": "43,90",
"s16": "54,00"
},
{
"s4": "87,15",
"s5": "87,40",
"s6": "87,80",
"s7": "87,90",
"s8": "88,05",
"s15": "121,05",
"s9": "88,60",
"s10": "87,30",
"s11": "88,00",
"s16": "80,90"
},
{
"s4": "108,00",
"s5": "108,25",
"s6": "108,60",
"s7": "108,70",
"s8": "108,85",
"s15": "119,65",
"s9": "109,30",
"s10": "108,50",
"s11": "109,00",
"s16": "92,25"
},
{
"s4": "",
"s5": "",
"s6": "2394,02",
"s7": "12,29",
"s8": "2395,46",
"s15": "",
"s9": "2386,92",
"s10": "22:05",
"s11": "",
"s16": ""
}
]
<table *ngIf="indexdata">
<tr style="color: #3B6593" >
<th><strong>Heizöl</strong></th>
<th><strong>Diesel</strong></th>
<th><strong>Benzin</strong></th>
<th><strong>Facht</strong></th>
</tr>
<tr *ngFor="let index of indexdata;let i=index">
<td>{{index.s4}}</td>
<td>{{index.s5}}</td>
<td>{{index.s6}}</td>
-----
-----
</tr>
</table>
Your code should be
<table *ngIf="indexdata">
<tr style="color: #3B6593">
<th><strong>Heizöl</strong></th>
<th><strong>Diesel</strong></th>
<th><strong>Benzin</strong></th>
<th><strong>Facht</strong></th>
</tr>
<tr>
<td *ngFor="let indexvalue of indexdata">
<table>
<tr *ngFor="let indexobj of indexvalue | keys">
<td>
{{indexobj.value}}
</td>
</tr>
</table>
</td>
</tr>
</table>
You could create a custom pipe to return the list of key for each element. Something like this:
#Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
transform(value, args:string[]) : any {
let keys = [];
for (let key in value) {
keys.push({key: key, value: value[key]});
}
return keys;
}
}