Reputation: 101
I wrote a function that gets and shows the "best player" from my array of objects (the player who has most likes). The function works fine and shows me what I want, but the browser shows me errors in the console, and the routing in my app is blocked (I can't navigate between components using routes)
this is my DashboardComponent Class
export class DashboardComponent implements OnInit {
bestPlayer:Player;
data:Player[]=[];
max:number =0;
constructor(private playerService : PlayerService ,private router: Router) { }
ngOnInit() {
this.playerService.getData().then(data => {
this.data = data;
for (var i = 0; i <= this.data.length; i++) {
if (this.data[i].likes>this.max) {
this.max=this.data[i].likes;
this.bestPlayer=this.data[i];
}
}
});
}
viewDetails(bestPlayer: Player):void {
this.router.navigate(['/detail',this.bestPlayer.id]);
}
}
This is my service:
import {Player} from './player';
import {PlayersData} from './muck-players';
import { Injectable } from '@angular/core';
@Injectable()
export class PlayerService {
players:any;
data:any;
Player:Player;
getData():Promise <Player[]> {
return Promise.resolve(PlayersData);
}
}
when I run the app the browser show me those errors :
TypeError: this.data[i] is undefined Error: Uncaught (in promise): Error: Cannot activate an already activated outlet Error: Uncaught (in promise): Error: Cannot activate an already activated outlet
when I delete whats in ngOninit()
and viewDetails()
function, routing starts working again and browser doesn't show me errors.
Any help please !
Upvotes: 3
Views: 3904
Reputation: 6932
I have fixed dozens of errors in the Plunker and added some missing routing features. The App is working just fine now please take a look at my forked Plunker over here
I fixed all the files paths and used in forEach
method in your component just like this:
ngOnInit() {
this.playerService.getData().then(data => {
data.forEach( (arrData) => {
if (arrData.likes>this.max) {
this.max=arrData.likes;
this.bestPlayer=arrData;
}
})
});
}
Demonstration:
Upvotes: 1
Reputation: 73357
As a sidenote, always when you provide a plunker, make sure it's a working one ;) When I got it working, there was only a couple of issue actually. There was nothing wrong with your routing. The first error you were getting
this.data[i] is undefined
is because of your for loop, you had marked that we should loop until i
matches the length of the array (or equal). But we need to remember that the index of arrays start with 0
. So the last iteration it was trying to read an index that was not present in your array. So you should add -1
to your for loop:
for (var i = 0; i <= this.data.length-1; i++)
or do
for (var i = 0; i < this.data.length; i++)
When this was fixed, it produces new issues. Since data is coming async, so by the time the template is rendered, your variable bestPlayer
is undefined. This can be fixed with safe navigation operator, or wrapping everything inside a div
with the condition that bestPlayer
has values. This need to be applied to both the detail page and the dashboard. With the dashboard:
<div *ngIf="bestPlayer">
<!-- code here -->
</div>
And in the detail page the same but using player
instead, as that is the variable you are using there.
As mentioned, you can also use the safe navigation operator.
These actually cleared the second error you also had.
Here's your fixed PLUNKER.
Upvotes: 3
Reputation: 58553
Hi the issue is with your service,
You are trying to loop through data that is not available,
You need to change the code , If you are using Observer as service then put you code inside .subscribe method,
If you are using promise then put your looping code inside .then() method.
Try to use this :
If you are returning promise from this.playerService.getData()
this service
this.playerService.getData().then((data) => {
this.data = data;
for (var i = 0; i <= this.data.length; i++) {
if (this.data[i].likes>this.max) {
this.max=this.data[i].likes;
this.bestPlayer=this.data[i];
}
})
If you are returning observable from this.playerService.getData()
this service
this.playerService.getData().subscribe((data) => {
this.data = data;
for (var i = 0; i <= this.data.length; i++) {
if (this.data[i].likes>this.max) {
this.max=this.data[i].likes;
this.bestPlayer=this.data[i];
}
})
Upvotes: 1