I'm trying to use an angular service to get users from a database. When doing a GET request IN the service, I can console.log(res)
and get the response. However, when I try to grab the data from another component, it always comes up undefined
. Please help.
users.service.ts
import { Injectable } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { HttpClient, HttpClientModule } from '@angular/common/http';
@Injectable()
export class UsersService {
constructor(
private http: HttpClient,
private route: ActivatedRoute
) { }
users: any;
getUsers() {
this.http.get('http://localhost:3000/api/users').subscribe(res => {
this.users = res;
return this.users;
});
}
}
app.component.ts
import { UsersService } from './users.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
providers: [ UsersService ]
})
constructor(
private http: HttpClient,
private route: ActivatedRoute,
private usersService: UsersService
) {
this.users = usersService.getUsers();
}
And when I try to use it in app.component.html ...
<div *ngFor="let user of users"></div>
users comes up undefined
If you are using your service to centralize your users data, then consider this:
import { Injectable } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { HttpClient, HttpClientModule } from '@angular/common/http';
@Injectable()
export class UsersService {
constructor(
private http: HttpClient,
private route: ActivatedRoute
) {
this.getUsers()
.subscribe(data => this.users = data);
}
users: any;
getUsers() {
return this.http.get('http://localhost:3000/api/users');
}
}
then in your component:
constructor(
private http: HttpClient,
private route: ActivatedRoute,
public usersService: UsersService <------ changed to public to make it available to the template
) {
// this.users = usersService.getUsers(); <------ commented out, as users is now centralized in the service
}
and in your template:
<div *ngFor="let user of usersService.users"></div>
By making these changes, your getUsers() method will only be called at the creation time of your UsersService (first time it appears in providers array) and your users data will be available to any component that injects UsersService.
The issue with your code is that you are returning within the subscription. Get is an async call Javascript doesn't know when it is going to return.
Quick Fix:
Get the prop directly After you make the REST call.
in your service:
this.http.get('http://localhost:3000/api/users').subscribe(res => {
this.users = res;
});
in your component:
usersService.getUsers();
this.users = usersService.users;
Change your service as
getUsers() {
return this.http.get('http://localhost:3000/api/users')
.map((response: Response) => response.json());
}
and use subscribe()
inside the component,
this.usersService.getUsers().subscribe((data) => {
this.users = data;
});
Your Service Class
import { Injectable } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { HttpClient, HttpClientModule } from '@angular/common/http';
@Injectable()
export class UsersService {
constructor(private http: HttpClient, private route: ActivatedRoute) { }
getUsers(): Observable<any> {
return this.http.get('http://localhost:3000/api/users')
.map(res => res.json())
.catch(this.handleError);
}
}
private handleError(error: Response) {
return Observable.throw(error || 'Server Error')
}
Your Component
import { UsersService } from './users.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
providers: [ UsersService ]
})
constructor(private http: HttpClient, private route: ActivatedRoute, private usersService: UsersService) {
this.usersService.getUsers().subscribe(
res => { this.users = res; },
err => { console.log(err); }
);
}
Make sure to import { Observable }