angular 2 ngFor Cannot read property of undefined - json

I have a nested object with data that I am trying to access with ngFor.
I am able to reach the first part of the data with the first ngFor (app_name, time_stamp etc)
But for some reason I am not getting to the nested object of test_cases. When I try it breaks the whole page and the console keeps telling me "Cannot read property 'test_cases' of undefined" and I can't seem to figure out why...
(first part of) data inside the component:
export class AppComponent {
tests = TESTS;
var TESTS: Test[] = [
{
"app_name": "website",
"time_stamp": "2018-01-20T12:00:00Z",
"test_cases": [
{
"test_name": "View article",
"status": true,
}]
}]
HTML partial:
<div id="tested-app" *ngFor = "let item of tests">
<h2>----<span> {{ item.app_name }} </span>----</h2>
<p id="time"> Time: <span> {{item.time_stamp}} </span> </p>
</div>
<div class="module" *ngFor="let subItem of item.test_cases">
<h3>{{subItem.test_name}}</h3>
</div>

For peeps who are struggling with this:
John Montgomery and Andres M answered this in the comments, I had to put the second div inside the first.

Related

How present JSON List in Angular HTML with *ngFor

I get a result in the JSON Format like these sample from a webservice.
How can i iterate over this items to prensent the objects
HTML Code - not working
<div *ngFor="let item of List">
{{item.Code}}
</div>
JSON Sample
"List": {
"0": {
"Code": "A"
},
"1": {
"Code": "B"
},
"2": {
"Code": "C",
}
}
unfortunally the webservice does not provide this as an Array [] of objects
I want to see the list of all items für the Key "Code"
You can use KeyValuePipe like here.
So the your code would be something like this:
<div *ngFor="let item of List | keyvalue">
{{item.value.Code}}
</div>
As it was not working with
<div *ngFor="let item of List | keyvalue">
{{item.value.Code}}
</div>
Typescript was throwing an error because {{item.value.Code}} was not known.
I did some additional research and found the following solution
<div *ngFor='let key of objectKeys(List)'>
{{List[key].Code}}
</div>
in the typescript class corresponding to the html file you have to add
objectKeys = Object.keys;

insert html tag in join method at angular 2+ not working

Is there any reason this is not working?
The <br> or any html tags is not interpreted.
in HTML:
{{data.prContent.join(' <br> ')}}
in Json file:
"prContent": [
"Banana",
"Orange",
"Apple",
"Mango"
],
How can I work around this?
If the parent element contains only that interpolation, you can set the content with [innerHTML]:
<div [innerHTML]="data.prContent.join('<br/>')"></div>
Otherwise, you can combine the array items with multiple interpolations, using an *ngFor loop:
<ng-container *ngFor="let item of data.prContent; let isLast = last">
{{item}} <br *ngIf="!isLast" />
</ng-container>
See this stackblitz for a demo.

when using a GET method data is coming in console not in HTML

I have written my get method inside ngOnInIt(). When I am printing data in console it is visible, but when printing in HTML using interpolation, it is returning [ object object]
{{filteredCourses}} ==> [object object]
and when i am using {{course.category|json}} so here i am getting all values of array ["course" : "database" , "category" : "database" , "length" : "2hr" ] thats how the value is coming
html :-
<div class="courses" fxLayout="row wrap" fxLayoutAlign="center" [#animateStagger]="{value:'50'}">
<div class="course" *ngFor="let course of filteredCourses" fxFlex="100" fxFlex.gt-xs="50"
fxFlex.gt-sm="33" [ngClass]="course.category" [#animate]="{value:'*',params:{y:'100%'}}">
<div class="course-content" fxLayout="column" fxFlex="1 1 auto">
<div class="header" fxLayout="row" fxLayoutAlign="center center"
[ngClass]="course.category + '-bg'">
<div class="category" fxFlex>
{{course.category|json}}
</div>
</div>
</div>
Code:
filteredCourses: any[];
this.product_name = getProduct()['name'];
console.log(this.product_name);
this.token = getToken();
this.httpHeaders = new HttpHeaders({ "Authorization": "Bearer " + this.token });
this._httpClient.get('http://127.0.0.1:8000/api/products/info/'+this.product_name+'/',{headers: this.httpHeaders})
.subscribe(
data => {
this.product = data;
this.courses = data['cources'];
this.filteredCourses = this.courses;
console.log(this.filteredCourses);
},
error => {
console.log(error);
}
);
try using JSON.stringify(yourObject) or maybe in certain cases you can use Object.keys().
You need to use loop if its an array of object or you might want to print the properties of object individually.
But if you want to see the object filteredCourses in template, use json pipe.
{{filteredCourses | json}}
In case you need help to print values using *ngFor or properties, do let us know.
I suppose filteredCourses collection contains an array of objects. So you need to iterate through filteredCourses using ngFor directive to render data in the HTML template.
Like:
<ul>
<li ngFor="let item of filteredCourses">{{item.courseName}}</li>
</ul>

get result from array of objects retrieved from db and return to ng-template

I have a complex array of objects retrieved from db
Link to the Code
let arr = [
{
"userId": "-jgtgjS",
"firstName": "def",
"lastName": "yellow",
"email": "def#gm.com",
"otp": 0,
"otpExpiry": "",
"mobileNumber": 9852145987,
"createdOn": "2019-09-15T11:50:29Z",
"gender": "female",
"profilePic": "",
"friendList": {
"_id": "5d7e25852fffaa2858930878",
"userId": "-jgtgjS",
"friendCount": 0,
"userObject": "5d7e25852fffaa2858930877",
"allFriends": [
{
"friendId": "GsbItTr",
"requestSent": true,
"requestReceived": false,
"friendSince": 1568549711731,
"_id": "5d7e2b2f25207f161c718a64",
"friendObject": "5d7e285aa6132b179cfa917c"
},
{
"friendId": "ch4PXXn",
"requestSent": false,
"requestReceived": true,
"friendSince": "",
"_id": "5d7f16124c7b3f16ec308c1d",
"friendObject": "5d7dce8d2a719a1d188ed641"
}
],
"__v": 2
}
}]
Link to the Code
I am using *ngFor to display the friends in my template, but I also need to show whether he is friend or not, how can I pass the instance of *ngFor before display to .ts and then compute the boolean and then return back to the template so that the user displayed is friend or not.
Added a pic. Now the button shows add friend in each using ngFor. but depending on the status of each user the button would change to accept if a request is received or it will show friends if the request is already accepted and friendSince has some value
I am able to get the status like this.
ar[0].friendList.allFriends.forEach(element=>{
if (element.friendId=='ch4PXXn'){
sent=element.requestSent;
received=element.requestReceived;
}
});
if u refer to the image added.. u can see there are many users listed in the view using *ngfor. 'def yellow' is one of them. Now inside of users object there is another array of objects which stores all the friend request transactions happening. This view is being seen by userId 'ch4PXXn'. So I need to find the object inside allFriends with a friendId containing ch4PXXn and then based on other parameters like sent, received, since. I want to show a button which will give user ch4PXXn options to accept or show request sent.
Link to the Code
Try like this:
<div *ngFor="let friend of arr">
<h3>{{friend.firstName}} {{friend.lastName}}</h3>
<h4>{{friend.gender}} </h4>
<h5>{{friend.email}} </h5>
<h5>{{friend.mobileNumber}} </h5>
<table>
<tr>
<th>Friend Id </th>
<th>Is Friend </th>
</tr>
<tr *ngFor="let item of friend.friendList.allFriends">
<td>{{item.friendId}}</td>
<td>{{item.friendSince == '' ? 'Not Friend' : 'Friend'}}</td>
</tr>
</table>
</div>
Working Demo
You can use a nested *ngFor, where you iterate the allFriends array, and based on your conditions show different content:
<ng-container *ngFor="let a of friend.friendList.allFriends; let last = last">
<!-- First check that friend matches the current user -->
<div *ngIf="a.friendId === loggedInUser">
<!-- are you already friends? -->
<p *ngIf="a.friendSince">You are friends!</p>
<!-- You have received a request, but not yet accepted -->
<button *ngIf="a.requestReceived && !a.friendSince> Accept Friend request</button>
<!-- You have sent request, but user hasn't accepted -->
<button disabled *ngIf="a.requestSent && !a.friendSince">Friend Request Sent</button>
</div>
<!-- All above conditions are false, and it is last item in array -->
<button *ngIf="a.friendId !== loggedInUser && last">Add Friend</button>
</ng-container>
Here's a STACKBLIZ

Get nested values from JSON with angularJS

I need to get nested products from JSON to my html in <div ng-repeat="order in orders"></div> I tried many versions of getting products values(name, description etc.) but none of them works. How to do this ?
JSON:
[
{
"id":3,
"date":"00:00:00",
"user":{
"id":1,
},
"orderState":{
"id":1,
},
"products":[
{
"id":1,
"name":"Bosch POF 1200",
"description":"1200W",
"enabled":true,
"price":459,
},
{
"id":9,
"name":"Graphite 58G782",
"description":"a",
"enabled":true,
"price":429,
}
]
}
]
Controller
OrdersService.retrieveAllByCurrentUser().then(function(response) {
$scope.orders = response.data;
console.log(response.data);
}, function(error) {
registerError(error, 'retrieving all orders');
});
The ng-repeat directive creates a new scope, which means that you should be able to loop through the products within it like this:
<div ng-repeat="order in orders">
<div ng-repeat="product in order.products"> e.g. {{product.name}} </div>
</div>
I would also advise to write a directive for dealing with that kind of stuff, because your code can get unreadable really fast. Don't take my word for it though as I am no Angular expert.
Create a nested ng-repeat like this to access the products information:
<div ng-repeat="order in orders">
<div ng-repeat="product in order.products">
<h1 ng-bind="product.name"></h1>
<p ng-bind="product.description"></p>
</div>
</div>
For each order it will go into order.products and loop out the information as product, then you can access the information in product via dot notation, like product.name for example.
You can do nested ng-repeat in html
<div ng-repeat="order in orders">
<div ng-repeat "product in order.products">
<span>{product.name}}</span>
<span>{{product.description}}</span>
</div>
</div>