I have a problem displaying a nested value from Localstorage in Angular. The problem is on the second *ngFor. The first *ngFor display well. The second ngFor has an error of "TypeError: Cannot read property 'toUpperCase' of undefined"? I don't know why the is toUppercase since i didn't use uppercase here
HTML
<mat-list-item role="listitem" *ngFor="let bookmark of bookmarks">
{{ extractNameFromJson(bookmark[1]).id }}
<ul>
<li *ngFor="let extractNameFromJson(bookmark[1])?.cuesData of bookmark">
{{ }}
</li>
</ul>
</mat-list-item>
TS
getAllBookmarks() {
this.bookmarks = Object.entries(localStorage);
console.log(this.bookmarks);
}
extractNameFromJson(obj) {
obj = JSON.parse(obj);
return obj;
}
You need to get the value of each bookMark as a variable in *ngFor
first. You cannot have a function call while extracting a variable from a loop using ngFor
. One way can be to have a pipe
which does this filtering for you while looping, or another way could be to use ng-container
to loop and only show lis
if your condtion passes.
<ng-container *ngFor="let eachBookMark of bookmark">
<ng-container *ngIf="extractNameFromJson(eachBookMark[1]) as data">
<ng-container *ngIf="data.cuesData">
<li *ngFor="data.cuesData">
{{data | json}}
</li>
</ng-container>
</ng-container>
</ng-container>
EDIT:
if you want to change the bookmarks
array in your ts, maybe you can do this:
this.bookmarks = this.bookmarks.map(([first, second]) => {
return [first, JSON.parse(second)];
});
Now, if you have done this, then your HTML can be simply:
<mat-list-item role="listitem" *ngFor="let eachBookMark of bookmarks">
<ul>
<ng-container *ngIf="eachBookMark[1].cuesData as cuesData">
<li *ngFor="let eachCue of cuesData">
{{ eachCue.description }}
</li>
</ng-container>
</ul>
</mat-list-item>
EDIT2:
this.filteredBookmarks = this.bookmarks.reduce((acc, [first, second]) => {
const parsedOb = JSON.parse(second);
if (parsedOb.cuesData) {
acc.push([first, parsedOb]);
}
return acc;
}, []);
<mat-list-item role="listitem" *ngFor="let eachBookMark of filteredBookmarks">
<ul>
<li *ngFor="let eachCue of cuesData">
{{ eachCue.description }}
</li>
</ul>
</mat-list-item>
All the above filtering, (map/reduce) would happen at the place where you are populating bookmarks
.