Not able to access json Object key - json

I have a json object as below:
Json
{error: false, message: [,…]}
Inside message:
{convid: "5aeab8a0e5dd7c55942a7ce7", recipient: "Akhil Sindhwani", seen: false, from: "Miti Desai",…}
convid : "5aeab8a0e5dd7c55942a7ce7" from : "Miti Desai" messages :
"asdsad" recipient : "Akhil Sindhwani" seen : false subject : "sasas"
updatedAt : "2018-05-03T07:22:09.367Z"
I am working in Angular and above is the response I get from http service.
Service function:
getUserMessages() {
console.log("getUserMessages");
this._mailingService.getMessages()
.subscribe(conversations => {
this.messageData = conversations
if (conversations) {
console.log( this.messageData);
this.messageData = conversations
}
})
, error => {
console.log("Error");
},
() => {
// THIS IS EXECUTED AFTER THE SUBSCRIBE COMPLETES
console.log( 'this.messageData');
console.log( this.messageData);
}
}
In code above I get a response in conversation which I get that json object.
I put that object in message data.
In html I tried to parse message data as follow:
<div id="messageMenu">
<ul>
<li class='msgBody' *ngFor = "let message of messageData.message">
<div class="msgListingContainer1">
<div class="senderImg">
<img src="../../../../assets/images/profile1.jpg">
</div>
</div>
<div style=" display:inline-block" class="msgListingContainer2">
<span style=" display:inline-block" class="senderName">{{message.recipients}}</span>
<span class="msgTimestamp">5:13pm</span>
<p class="msgheading"><span>Hey alex pretty cool new track you got..</span></p>
</div>
</li>
</ul>
</div>
But I get this error message:
MessageMenuComponent.html:6 ERROR TypeError: Cannot read property
'message' of undefined
I am trying to fetch a key from json and then loop it using ngFor directive it. It is simple, I have done this before.
Can anyone tell me what I am doing wrong?
Any help would be appreciated!
Update
Not sure how it worked.
Didn't change anything in component file.
Changed html to:
<div id="messageMenu">
<ng-container *ngIf="showConversations;else noCnvrstns" >
<ul>
<li class='msgBody' *ngFor = "let message of messageData">
<div class="msgListingContainer1">
<div class="senderImg">
<img src="../../../../assets/images/profile2.jpg">
</div>
</div>
<div style=" display:inline-block" class="msgListingContainer2">
<span style=" display:inline-block" class="senderName">{{message.recipient}}</span>
<span class="msgTimestamp">{{ message.updatedAt | date:'hh:mm a' }}</span>
<p class="msgheading">{{message.messages}}</p>
</div>
</li>
</ul>
</ng-container>
<ng-template #noCnvrstns>
<div class="noConversations">No conversations to show</div>
</ng-template>
</div>
Started getting response.
I didn't understand when messages were in message key of json object then how I able to fetch them out of conversations directly but working for me.
Not adding answer as question itself is ambiguous.
Thanks for help!

Better to use safe navigation ? in case of asnyc calls fetching data. it will not alow angular to throw an error.
Try this -
<li class='msgBody' *ngFor = "let message of messageData?.message">
Also at the time of declaration typecaste messageData: any.

Your JSON file is malformed.
How you can read here:
In JSON, keys must be strings, written with double quotes
Insert double quotes around your keys, this will probably fix the problem.

Related

Property 'name' does not exist on type 'string' ngFor in Angular

I got this error while trying to display an array of objects
Error: src/app/components/timeline/timeline.component.html:9:29 - error TS2339: Property 'name' does not exist on type 'string'.
<h4>{{publication.user.name}}</h4>
~~~~
src/app/components/timeline/timeline.component.ts:10:15
10 templateUrl: './timeline.component.html',
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component TimelineComponent.
in my timeline.component.html I have this:
<div id="publications">
<div *ngFor = "let publication of publications" class="item-publication">
<div class="panel panel-default">
<div class="panel-body">
<h4>{{publication.user.name}}</h4>
</div>
</div>
</div>
</div>
and this is the getPublications function that I have
getPublications(page){
this._publicationService.getPublications(this.token, page).subscribe(
response => {
console.log(response);
if(response.publications){
this.total = response.total_items;
this.pages = response.pages;
this.publications = response.publications;
if(page > this.pages){
this._router.navigate(['/home']);
}
}else{
this.status= 'error';
}
},
error =>{
var errorMessage = <any>error;
console.log(errorMessage);
if(errorMessage != null){
this.status = 'error';
}
}
);
}
If I make a console.log(response) it shows me the values of the array and the properties are correct (name,surname,email, text etc)
In the HTML code, when I do the loop for the publication's text <h4>{{publication.text}}</h4> it works and even if I use <h4>{{publication.user}}</h4> it shows a list of Objects.
I'm taking an online course and basically copying what the teacher does line by line but IDK why when I try to display name and surname properties, it shows the error that I told you
Thank you for your help.
I found the solution and is related to TS type system so basically I have a model object called publication.ts which includes:
export class Publication{
constructor(
public _id:string,
public text: String,
public file: String,
public created_at: String,
public user: String
){}
}
And the issue was related to the type for the property user so by changing its type to public user: any it worked and now it shows the required fields. Sorry for posting this without a deep search before ask for help. Newbie mistakes
Thanks for the help
You are subscribing to the data so there is a small delay in getting the data. Wrap the tag with a *ngIf to wait for the data to be available.
<div *ngIf="publications" id="publications">
<div *ngFor = "let publication of publications" class="item-publication">
<div class="panel panel-default">
<div class="panel-body">
<h4 *ngIf="publication && publication.user && publication.user.name">{{publication.user.name}}</h4>
</div>
</div>
</div>
</div>

JSON data undefined while using in HTML

I am new to Angular and Node and have been working on a full stack development. I am reading the data on Angular from Node which I have connected to MySQL. I am somehow stuck at outputting my data on an HTML page. I am getting the error of undefined when I try to access my data in my HTML.
This is the JSON data that I have read on my console
This is my typescript code that converts JSON object to string:
private onFetchPosts()
{
this.http
.get<{[key: string]: DataBase}>('http://localhost:3000/show') //Here, DataBase is an interface
.pipe(map(responseData => {
const postsArray: DataBase[] = [];
for (const key in responseData){
if(responseData.hasOwnProperty(key)){
postsArray.push({...responseData[key], idoffice: key});
}
}
return postsArray;
}))
.subscribe(posts => {
this.dbData = posts;
console.log(this.dbData);
});
}
When I try to access this data in my HTML code:
<h3>test print</h3>
<li class="list-group-item" *ngFor = "let db of dbData"></li>
<p>{{ db.ActivityType }}</p>
Then, I get this error:
ERROR TypeError: Cannot read property 'ActivityType' of undefined
Can you please help me out?
use db.ActivityType inside li .
<li class="list-group-item" *ngFor = "let db of dbData">
<p>{{ db.ActivityType }}</p>
</li>
<h3>test print</h3>
<li class="list-group-item" *ngFor = "let db of dbData">
<p>{{ db.ActivityType }}</p>
</li>
li tag closed wrongly.

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 an arraylist from a service using HTTP in ANGULAR

i have a component named zoomdetails which contains the specific details of a product
when i click on the product image the zoomdetails component displays and contains the details of the clicked product
so i m using route and adding the id of the product to the URL
the problem is :
when i load the products arraylist from the service and try to get the product by its id and looping the arraylist an error appears and indicates Cannot read property 'length' of undefined
here is the zoomdetails.component.ts code :
(i ve added some log.console comments to see the results)
export class ZoomdetailsComponent implements OnInit {
x: string="";
produitzoom:IProduct;
produits:IProduct[];
errormessage1 :string ;
currentId : number;
constructor(private _route:ActivatedRoute,private _router:Router,private _productServic:ProductdataService)
{
console.log("Logging the route : " + JSON.stringify(_route.snapshot.params));
this.currentId = +_route.snapshot.params['id'];
console.log("Logging the current ID : " + this.currentId)
this._productServic.getProducts()
.subscribe(productss => this.produits=productss ,error=>this.errormessage1= <any>error);
console.log("************************************************************************************")
}
Myspan(){
this._router.navigate(['/']);
}
find (id:number,P:IProduct[]) :IProduct{
console.log("+++++++DANS FIND ERROR +++++++++++++++++++++++++")
for (let product of P )
{
if (product.idpr==id )
{
return product;
}
}
}
ngOnInit() {
console.log("-------------DANS NGONINITTT-------------------------------------------------------------")
this.produitzoom=this.find(this.currentId,this.produits)
console.log(this.produitzoom.productName)
console.log("--------------------------------------------------------------------------")
}
and this is my zoomdetails component .html
<router-outlet></router-outlet>
<div id="zoom" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close" (click)="Myspan()">×</span>
<div class="container">
<div class="row">
<div class="col-md-4 item-photo">
<img src={{produitzoom.imgUrl}} style="width:360px;height:650px;">
</div>
<div class="col-md-6" style="border:0px solid rgba(163, 152, 152, 0.856)">
<span class="pull-right">
<!-- Datos del vendedor y titulo del producto -->
<h1>{{produitzoom.productName}}</h1>
<h4 style="color:#337ab7"> {{produitzoom.author}} <small style="color:#337ab7">(50 ventes)</small></h4>
<!-- Precios -->
<h2 class="title-price"><small>Price</small></h2>
<h3 style="margin-top0px">{{produitzoom.price}} $</h3>
<br> <br>
<!-- Detalles especificos del producto -->
<div class="section" style="background:rgb(222, 228, 222);">
<h5 class="title-attr" >
<div>
<br>
{{produitzoom.description}}
<br> <br>
</div>
</h5>
</div>
<br><br>
<!-- Botones de compra -->
<script>
console.log("Test of value : " + JSON.stringify(produitzoom))
</script>
<button class="btn btn-success right" [routerLink]="['/Authentification',produitzoom]">
<span class="glyphicon glyphicon-shopping-cart"></span> Add to Cart
</button>
</span>
<br> <br> <br> <br>
<ul class="menu-items">
<li class="active">Customers Reviews</li>
</ul>
<div style="width:100%;border-top:1px solid silver">
<p style="padding:15px;">
<small>
Stay connected either on the phone or the Web with the Galaxy S4 I337 from Samsung. With 16 GB of memory and a 4G connection, this phone stores precious photos and video and lets you upload them to a cloud or social network at blinding-fast speed. With a 17-hour operating life from one charge, this phone allows you keep in touch even on the go.
With its built-in photo editor, the Galaxy S4 allows you to edit photos with the touch of a finger, eliminating extraneous background items. Usable with most carriers, this smartphone is the perfect companion for work or entertainment.
</small>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
and these are the errors :
Logging the route : {"id":"1"} zoomdetails.component.ts:22 Logging the current ID : 1 zoomdetails.component.ts:25 ************************************************************************************ zoomdetails.component.ts:50 -------------DANS NGONINITTT------------------------------------------------------------- zoomdetails.component.ts:38 +++++++DANS FIND ERROR +++++++++++++++++++++++++ ZoomdetailsComponent_Host.html:1 ERROR TypeError: Cannot read property 'length' of undefined (from the find method )
ERROR TypeError: Cannot read property 'imgUrl' of undefined (from the html file produitzoom.imgurl)
what should i do !
first, about the imgUrl error, because of the fact that initially produitzoom is undefined, and it gets it's value after an async call, you can change the value of binding to this: [src]="produitzoom? produitzoom.imgUrl : null".
also about the other error, you are calling this.produitzoom=this.find(this.currentId,this.produits) inside your ngOnInit function, but again, bacuase of the fact that the produits is also undefined at the beginning of the component's lifecycle, and gets it's value after an async call. you should move that this.find() call over to the subscribtion's success. something like this:
productss => {
this.produits=productss;
this.produitzoom = this.find(this.currentId,this.produits)
}
Note!!
it's also very important and recommended that if you are subscribing to an observable, you unsubscribe it at the end of that component's Lifecycle (inside ngOnDestroy function). otherwise, this would cause memory leeks and untracable errors... you can do that by defining a property for subscription like:
productsSubscription: Subscription;
dont forget to import Subscription from rxjs/subscription. and then assign the subscription to this property like:
this.productsSubscription = this._productServic.getProducts()
.subscribe(.....);
and inside ngOnDestroy:
ngOnDestroy(){
if(this.productsSubscription){
this.productsSubscription.unsubscribe();
}
}
have that if there to prevent any undefined-related errors.
The problem is that you are loading the products in your constructor, which is asynchronous. Then in your ngOnInit function that is called later on you're using the result of those loaded products, but unfortunately they seem to be not loaded yet. Therefore your P array is not existing yet and so you are using an undefined object in a for loop, which is not working.
ngOnInit() {
console.log("-------------DANS NGONINITTT-------------------------------------------------------------")
// --> here you use the products from the constructor
// but they are not loaded yet, because the loading process takes time and is asynchronous
this.produitzoom=this.find(this.currentId,this.produits)
console.log(this.produitzoom.productName)
console.log("--------------------------------------------------------------------------")
}
What you should do is place the loading of your products in the ngOnInit function as well. There you can wait for the result and then call the find function.
nOnInit(){
// don't subscribe in the constructor, do it in the ngOnInit
this._productServic.getProducts().subscribe(productss => {
// now the results are here and you can use them
this.produits = productss;
// only then you can call the find function safely
this.produitzoom = this.find(this.currentId, this.produits)
}, error => this.errormessage1 = <any>error);
}

Item in loop is undefined

I have an issue that I don't understand, and if anyone can help, I would appreciate it.
I am using Ionic2 with Meteor/MongoDb.
I have a cursor:
private messages: Mongo.Cursor<Message>;
On the server I do an insert:
Messages.insert({
chatId: chatId,
senderId: senderId,
content: content,
readByReceiver: false,
createdAt: new Date()
});
It triggers an observable as expected:
this.messages.observe({
added: (message) => this.addMessageToLocal(message)
});
private addMessageToLocal(newMessage: Message): void {
// here I print the message, and it is as expected
}
Also, I do a forEach through the messages, and they are all populated as expected.
Issue
My problem is in the html. I loop trough the messages cursor. It displays each item as expected. Until I add a message (as above). Then the new message from the html is undefined.
<template ngFor let-message [ngForOf]="messages">
<div *ngIf="!exists(message)" class="message-wrapper">
<div *ngIf="message.changeDate">
<center><span class="message-datetime">{{message.createdAt | amDateFormat: 'DD MMM YYYY'}}</span></center>
</div>
<div [class]="'message message-' + message.ownership">
<div class="message-content">server:{{message.content}}</div>
<span class="time-tick">
<span *ngIf="message" class="message-timestamp">{{message.createdAt | amDateFormat: 'h:mm a'}}</span>
<div *ngIf="message && message.readByReceiver && senderId == message.senderId">
<span class="checkmark">
<div class="checkmark_stem"></div>
<div class="checkmark_kick"></div>
</span>
</div>
</span>
</div>
</div>
</template>
The final message item in the loop (the new one added), is undefined. i.e. In the *ngIf="!exists(message)" function called from the html, I print the message, and its's undefined.
So in the html I loop over the messages Cursor, and the new one is undefined. However, if even in the same function (exists()), I loop over the messages Cursor again, just to test it, none of the items are undefined.
Question
Please can anyone suggest what I can do to not have the last item in the Cursor as undefined?
Thanks
UPDATE
I am getting something I don't understand.
When I call a function from the html as follows, message is not undefined:
{{ formatMessage(message) }}
But if I call a function as follows, it is undefined:
*ngIf="!exists(message)"
I solved this by using:
changeDetection: ChangeDetectionStrategy.OnPush,
But I still think there may be a bug in Angular