Reputation: 166
I've done the angular2 quickstart and the tour of heroes tutorial from the angular site in order to get acquaintanced with it, and after getting it running I felt like the next step was adding a database connection using nodejs
and koa
to the tour of heroes app to add a little more scalability. I've followed https://github.com/mahalo1984/TourOfHeroesWithMongoDb this tutorial for the most part, changed the db from mongo to mysql and adapted what I needed.
I've upladed my code to https://github.com/nagarz/HeroEditor for the ones who want to see all the code.
I've got the database setup working and I get the query result json formatted, but when I try to pick it up with the getHeroes service which should convert send a promise to the template, I get this
EXCEPTION: Uncaught (in promise): TypeError: Cannot read property 'slice' of undefined
I'm kinda new to JS, and I was getting most of it, and I was able to fix errors given the log, but this one is something I can't get past, this one. I'm not a JS/angular2 wizard, but from what I get the json is not being picked properly by the service and when it tries to convert it into an array and slice it to get X amount of elements from it, it gives the error. I've tried different stuff to get it working but no dice, so I figured I'd ask here hoping that someone better than me (not that hard, feelsbadman) can see what's the problem and point me to it so I can finish the whole setup.
This is the route I use to query the database
router.get('/api/heroes', function* (){
var rows = yield db.query("select * from heroes");
this.body = { heroes: rows };
});
When I enter the url http://localhost:3333/api/heroes
in my browser I get the result in json like this
{"heroes":[{"id":1,"hid":1,"name":"Saitama"},{"id":2,"hid":2,"name":"Genos"},{"id":3,"hid":3,"name":"Watchdog Man"},{"id":4,"hid":4,"name":"Metal BAt"},{"id":5,"hid":5,"name":"Puri Puri Prisoner"},{"id":6,"hid":10,"name":"Speed of sound, Sonic"},{"id":7,"hid":11,"name":"Tatsumaki"}]}
And this is where I obtain the response and try to convert it into an array for processing the info in the app.
@Injectable()
export class HeroService {
private headers = new Headers({'Content-Type': 'application/json'});
...
private getHeroesUrl = 'http://localhost:3333/api/heroes';
constructor(private http: Http) {}
//this is the method in question
getHeroes(): Promise<Hero[]> {
return this.http.get(this.getHeroesUrl).toPromise().then(response => response.json().data as Hero[]).catch(this.handleError);
}
}
This is the Hero
model class:
export class Hero {
hid: number;
name: string;
}
This is the class where method from the service is called, and the obtained array is sliced, and the point where I'm getting the Exception
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
...
ngOnInit(): void {
this.heroService.getHeroes().then(heroes => this.heroes = heroes.slice(1, 4));
}
...
}
This is the full stacktrace of the exception:
Unhandled Promise rejection: Cannot read property 'slice' of undefined ; Zone: angular ; Task: Promise.then ; Value: TypeError: Cannot read property 'slice' of undefined
at eval (http://localhost:3000/app/components/dashboard.component.js:22:91)
at ZoneDelegate.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:203:28)
at Object.onInvoke (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:6242:41)
at ZoneDelegate.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:202:34)
at Zone.run (http://localhost:3000/node_modules/zone.js/dist/zone.js:96:43)
at http://localhost:3000/node_modules/zone.js/dist/zone.js:462:57
at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:236:37)
at Object.onInvokeTask (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:6233:41)
at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:235:42)
at Zone.runTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:136:47) TypeError: Cannot read property 'slice' of undefined
at eval (http://localhost:3000/app/components/dashboard.component.js:22:91)
at ZoneDelegate.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:203:28)
at Object.onInvoke (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:6242:41)
at ZoneDelegate.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:202:34)
at Zone.run (http://localhost:3000/node_modules/zone.js/dist/zone.js:96:43)
at http://localhost:3000/node_modules/zone.js/dist/zone.js:462:57
at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:236:37)
at Object.onInvokeTask (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:6233:41)
at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:235:42)
at Zone.runTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:136:47)
Upvotes: 1
Views: 776
Reputation: 81
The in-memory-web-api
module has a breaking change:
As of v0.5.0 (5 October 2017), the dataEncapsulation configuration default changed from false to true. The HTTP response body holds the data values directly rather than an object that encapsulates those values, {data: ...}. This is a breaking change that affects almost all existing apps!
So, in the example, change this:
getHeroes(): Promise<Hero[]> {
return this.http.get(this.heroesUrl)
.toPromise()
.then(response => response.json().data as Hero[])
.catch(this.handleError);
}
to:
getHeroes(): Promise<Hero[]> {
return this.http.get(this.heroesUrl)
.toPromise()
.then(response => response.json() as Hero[])
.catch(this.handleError);
}
Upvotes: 4
Reputation: 306
Looks like you are expecting an array to be returned but the data is actually an Object. Try this
getHeroes(): Promise<Hero[]> {
return this.http.get(this.getHeroesUrl).toPromise().then(response => response.json().data.heroes as Hero[]).catch(this.handleError);
}
your hero array is nested under a 'heroes' key in a JSON data structure.
Upvotes: 2