I am new to Angular (and Javascript for that matter). I've written an Angular service which returns an array of users. The data is retrieved from an HTTP call which returns the data in JSON format. When logging the JSON data returned from the HTTP call, I can see that this call is successful and the correct data is returned. I have a component which calls the service to get the users and an HTML page which displays the users. I cannot get the data from the service to the component. I suspect I am using the Observable incorrectly. Maybe I'm using subscribe incorrectly as well. If I comment out the getUsers call in the ngInit function and uncomment the getUsersMock call, everything works fine and I see the data displayed in the listbox in the HTML page. I'd like to convert the JSON data to an array or list of Users in the service, rather then returning JSON from the service and having the component convert it.
Data returned from HTTP call to get users:
[
{
"firstName": "Jane",
"lastName": "Doe"
},
{
"firstName": "John",
"lastName": "Doe"
}
]
user.ts
export class User {
firstName: string;
lastName: string;
}
user-service.ts
...
@Injectable
export class UserService {
private USERS: User[] = [
{
firstName: 'Jane',
lastName: 'Doe'
},
{
firstName: 'John',
lastName: 'Doe'
}
];
constructor (private http: Http) {}
getUsersMock(): User[] {
return this.USERS;
}
getUsers(): Observable<User[]> {
return Observable.create(observer => {
this.http.get('http://users.org').map(response => response.json();
})
}
...
user.component.ts
...
export class UserComponent implements OnInit {
users: User[] = {};
constructor(private userService: UserService) {}
ngOnInit(): void {
this.getUsers();
//this.getUsersMock();
}
getUsers(): void {
var userObservable = this.userService.getUsers();
this.userObservable.subscribe(users => { this.users = users });
}
getUsersMock(): void {
this.users = this.userService.getUsersMock();
}
}
...
user.component.html
...
<select disabled="disabled" name="Users" size="20">
<option *ngFor="let user of users">
{{user.firstName}}, {{user.lastName}}
</option>
</select>
...
!!! UPDATE !!!
I had been reading the "heroes" tutorial, but wasn't working for me so I went off and tried other things. I've re-implemented my code the way the heroes tutorial describes. However, when I log the value of this.users, it reports undefined.
Here is my revised user-service.ts
...
@Injectable
export class UserService {
private USERS: User[] = [
{
firstName: 'Jane',
lastName: 'Doe'
},
{
firstName: 'John',
lastName: 'Doe'
}
];
constructor (private http: Http) {}
getUsersMock(): User[] {
return this.USERS;
}
getUsers(): Promise<User[]> {
return this.http.get('http://users.org')
.toPromise()
.then(response => response.json().data as User[])
.catch(this.handleError);
}
...
Here is my revised user.component.ts
...
export class UserComponent implements OnInit {
users: User[] = {};
constructor(private userService: UserService) {}
ngOnInit(): void {
this.getUsers();
//this.getUsersMock();
}
getUsers(): void {
this.userService.getUsers()
.then(users => this.users = users);
console.log('this.users=' + this.users); // logs undefined
}
getUsersMock(): void {
this.users = this.userService.getUsersMock();
}
}
...
!!!!!!!!!! FINAL WORKING SOLUTION !!!!!!!!!!
This is all the files for the final working solution:
user.ts
export class User {
public firstName: string;
}
user.service.ts
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import { User } from './user';
@Injectable()
export class UserService {
// Returns this JSON data:
// [{"firstName":"Jane"},{"firstName":"John"}]
private URL = 'http://users.org';
constructor (private http: Http) {}
getUsers(): Observable<User[]> {
return this.http.get(this.URL)
.map((response:Response) => response.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));
}
}
user.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { User } from './user';
import { UserService } from './user.service';
@Component({
moduleId: module.id,
selector: 'users-list',
template: `
<select size="5">
<option *ngFor="let user of users">{{user.firstName}}</option>
</select>
`
})
export class UserComponent implements OnInit{
users: User[];
title = 'List Users';
constructor(private userService: UserService) {}
getUsers(): void {
this.userService.getUsers()
.subscribe(
users => {
this.users = users;
console.log('this.users=' + this.users);
console.log('this.users.length=' + this.users.length);
console.log('this.users[0].firstName=' + this.users[0].firstName);
}, //Bind to view
err => {
// Log errors if any
console.log(err);
})
}
ngOnInit(): void {
this.getUsers();
}
}
See Question&Answers more detail:
os