hello i am learning angular 6 and i am creating a simple app where i get data from API using Services Module and data is coming from API but when i try to display in view it gives error below is my code please help me what i am doing wrong.
Comoponent
export class LibraryComponent implements OnInit {
users$: Object;
constructor(private data: DataService) { }
ngOnInit() {
this.data.getLibrary().subscribe(
data => this.users$ = data
);
}
}
HTML
<h1>{{users.artist.name}}</h1>
API Data
{
"artist":{
"name":"Bebe Rexha",
"mbid":"db8fad3a-e131-47a1-8782-c2ee93708cdd",
"url":"https://www.last.fm/music/Bebe+Rexha",
"image":[
{
"#text":"https://lastfm-img2.akamaized.net/i/u/34s/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":"small"
},
{
"#text":"https://lastfm-img2.akamaized.net/i/u/64s/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":"medium"
},
{
"#text":"https://lastfm-img2.akamaized.net/i/u/174s/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":"large"
},
{
"#text":"https://lastfm-img2.akamaized.net/i/u/300x300/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":"extralarge"
},
{
"#text":"https://lastfm-img2.akamaized.net/i/u/300x300/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":"mega"
},
{
"#text":"https://lastfm-img2.akamaized.net/i/u/300x300/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":""
}
],
"streamable":"0",
Error
LibraryComponent.html:1 ERROR TypeError: Cannot read property 'artist' of undefined
at Object.eval [as updateRenderer] (LibraryComponent.html:1)
users$ is undefined in your ts initially and on subscribing to the data from the observable it assigns a value to the users$ property.
<h1>{{users$?.artist.name}}</h1>
The ? here handles the undefined problem.
In the assigning user to the "users$" variable but in the html you are referring to the wrong reference "users".
Please use ? safe navigation operator of angular. it will not throw any error if value is not available.
<h1>{{users$?.artist?.name}}</h1>
Related
This question already has answers here:
Angular2: Cannot read property 'name' of undefined
(7 answers)
Closed 3 years ago.
I am using an environment variable to be able to read something from a JSON and display in my HTML. My issue is that my HTML is trying to read the environment variable before it has been defined in the .ts and therefore I get an error.
I am currently defining the variable in ngOnit() but this gives me an error. I am using httpclient to be able to read the JSON (from a server) and obviously what is happening is that the variable is being read in the HTML before httpclient has got the data.
HTML
<p>Player One is: {{ id.playerone }} </p>
.ts
import { HttpClient } from '#angular/common/http';
export class ApComponent implements OnInit {
id: any = [];
constructor(private httpService: HttpClient) { }
ngOnInit() {
this.httpService.get('http://server/info.json').subscribe(
result => {
this.id = result;
},
error => {
console.log('Error Occured', error);
}
);
}
}
JSON
{
"playerone":"ajf806",
"playertwo":"hof934"
}
I get the expected output of Player One is: ajf806 but I also get an error in the console which is:
ERROR TypeError: Cannot read property '0' of undefined.
It does work and I get the output but I don't want to have the error in the console. Is there a way to delay the HTML reading the environment variable until the JSON has been read?
Change your variable like this:
id: any;
also change your template like this:
<p>Player One is: {{ id?.playerone }} </p>
Another version of the above code [a bit better]:
import { HttpClient } from '#angular/common/http';
export class ApComponent implements OnInit {
id$: Observable<any>;
constructor(private httpService: HttpClient) { }
ngOnInit() {
this.id$ = this.httpService.get('http://server/info.json')
.pipe(
catchError((error) => {
//handle your error
console.log(error);
})
)
);
}
}
Now change your template to make use of async pipe like this:
<ng-conatiner *ngIf="(id$ | async) as id">
<p>Player One is: {{ id.playerone }} </p>
</ng-container>
NOTICE - you are not subscribing to the observable in your component. async pipe is taking care of subscription management [i.e. subscribing/unsubscribing.].
I, for the life of me cannot understand why I can't access a property on an angular 6 class. Here is some code:
#Component({
selector: 'admin-badge-component',
templateUrl: './badge.component.html'
})
export class AdminBadgeComponent implements OnInit {
// Badge Object
public badgeObject: IVisitorBadge = null;
// On Init
public ngOnInit() {
this.route.params.subscribe((params) => {
// Get Badge Object From API
this.visitorService.getVisitorBadge(params['aid'],params['vid'])
.subscribe((response: IVisitorBadge) => {
console.log(response);
this.badgeObject = response;
});
});
}
}
the console.log outputs every thing as intended:
{
"id":2,
"visit_id":325,
"visitor_id":45,
"created_at":"2018-09-29 15:00:10",
"updated_at":"2018-09-29 15:00:10",
"visitor": {
...
"firstname": "matthew",
"lastname": "brown",
...
}
}
However, when I goto access and display the visitor firstname in my template using the following code:
<div>
<h3>
{{ badgeObject?.visitor?.firstname }} {{ badgeObject?.visitor?.lastname }}
</h3>
</div>
Nothing displays. If I try to access the properties directly without the ? notation, I get cannot access 'firstname' of undefined. Even if I wrap the template in *ngIf and check for property first. I've also tried initting and setting a loadingBool that gets set to false after I have the API response, and using it in the *ngIf still nothing.
Here is screenshot of full class: https://imgur.com/a/eEfCSL3
public constructor(private _change: ChangeDetectorRef) { }
this.visitorService.getVisitorBadge(params['aid'],params['vid'])
.subscribe((response: IVisitorBadge) => {
this.badgeObject = response;
this._change.markForCheck();
});
});
You have to tell the change detector that the component is dirty when you lazy load data. The first time the template is rendered the value of badgeObject is null, but later it is assigned a value.
Use the ChangeDetectorRef:
https://angular.io/api/core/ChangeDetectorRef
Found the issue. Not mentioned above is the this.visitorService.getVisitorBadge method, which I was accidentally setting the responseType to text in the HttpClient callout. Reset that back to json, now it's working.
I have errors in my services. I'm trying to grab a list of medias (which was created by NodeJS, and that launches a JSON with all media). I can recover it but I have a "Property 'medias' error does not exist on the type 'Media []'".
Here is my service
getMedias(): Observable<Media[]> {
return this.http
.get<Media[]>('http://localhost:3000/api/media')
.map(mediasFetched => mediasFetched.medias); <strong><!> L'erreur est juste ici <!></strong>
}
My component where I get the media:
this.mediaService.getMedias().subscribe(mediasFetched => {
this.medias = mediasFetched;
this.isLoading = false;
});
If I do not add ".medias" to "mediasFetched" I only get an object that contains my table. I have to go through this property to get my table and that's where my mistake is.
I have to go through this property to browse it with a ngFor in my html.
Excuse me in advance if I miss a big thing, but I start with Angular: p
Thank you
In your model, try adding this medias: any[]
export interface Media {
medias: any[]
}
I solved my problem, with <{medias: Media[]}>, remove the observable and add subscribe on my service.
Service:
getMedias() {
this.http
.get<{ medias: Media[] }>(`${this.apiUrl}media`)
.subscribe(mediasData => {
this.medias = mediasData.medias;
this.mediasUpdated.next([...this.medias]);
});
}
component.ts:
this.mediaService.getMedias();
#yer Thank you for your alternative
I have created my own directive, that hides content if user is not logged: *onlyUser. When I try to use it in component that utilises ng/animation I sometimes get an error:
Cannot read property 'insertNode' of undefined at TransitionAnimationEngine
Directive looks like this:
export class OnlyUserDirective {
constructor(private _templateRef: TemplateRef<any>,
private _viewContainer: ViewContainerRef,
private _userContextService: UserContextService) {
this._userContextService.isLogged$().subscribe(x => {
if (x === true) {
this._viewContainer.createEmbeddedView(this._templateRef);
} else {
this._viewContainer.clear();
}
});
}
}
And when I try to use it within a component with #Component({ animations: [...] }) I sometimes get the error from this question's beginning. Is this expected behavior, or an angular bug?
It is a known bug -> https://github.com/angular/angular/issues/19712.
I am checking if it is working with Angular 5
ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'title' of undefined
I used the same code from 'heroes' example to load a detail object in a single route. I kept getting this error because, I think, the data is not loaded before the view already started to render and that's why I am getting this error.
I had this problem to display "currentUser.name" which I solved by using currentUser?.name but in this case, it doesn't make sense to add to all the places of the object properties with '?'.
I have to spend more time in OnInit than what heroes example did. Because I need to fetch more stuff. So I know that the view just kicks in much earlier than the binding object journal is loaded.
ngOnInit() {
this.userService.getUser().then( (user) => {
this.currentUser = user;
this.accountsService.getAccounts().then( (accounts) => {
this.accounts = accounts;
this.userAccounts = this.currentUser.accounts.map(
accountId => this.accounts.find(
elem => elem.id == new String(accountId)
)
);
this.route.params
.switchMap((params: Params) => this.journalService.getJournal(+params['id']))
.subscribe( (journal) => {
console.log("journal", journal);
this.journal = journal;
});
});
});
}
How can I instruct the view to wait until the data is loaded before it starts to render itself?
Or is there something wrong with the code?
You could wrap your template with a condition.
Steps:
1 - Create a variable and initializes it with a falsy value:
loaded: boolean = false;
2 - Set it to true when your request is finished:
this.route.params
.switchMap((params: Params) => this.journalService.getJournal(+params['id']))
.subscribe((journal) => {
console.log("journal", journal);
this.journal = journal;
this.loaded = true; // -> here
});
3 - In your template use *ngIf to prevent errors:
<ng-container *ngIf="loaded">
... content
</ng-container>