'Cannot read property 'subscribe' of undefined angular
I have a service UserService that has a method getUsers() and this service is shared among different angular components.
The method calls an API and returns the data. I want to hold the result/state of last API call so I used BehaviorSubject to hold the last state so that if different components call getUsers() there should be only one API call otherwise hold state must be returned.
This is how I am implementing this
private _users$: BehaviorSubject<User[]>;
constructor(private http: HttpClient) {
this._users$ = new BehaviorSubject([]);
}
getUsers(): BehaviorSubject<User[]> {
if (!this._getUsersState().length) {
this._loadUsers();
this._users$.subscribe(() => {
return this._users$;
});
} else {
return this._users$;
}
}
_loadUsers() {
let _users$ = this.http.get(`${this._context}/users/`);
_users$.subscribe((users: User[]) => {
this._users$.next(Object.assign([], users));
});
}
_getUsersState(): User[] {
return this._users$.getValue();
}
And in the component
this.userService.getUsers().subscribe((users: any) => {
console.log(users);
});
but I am getting the following error
ERROR TypeError: Cannot read property 'subscribe' of undefined
I guess get users returns automatically if the length is 0.
How can I solve this issue? And is this approach good?
Solution 1:[1]
Edit your service like this :
private _users$ = new BehaviorSubject<User[]>(null);
public usersChanged = this._users$.asObservable();
constructor(private http: HttpClient) {
}
getUsers(): BehaviorSubject<User[]> {
if (!this._getUsersState().length) {
this._loadUsers();
this._users$.subscribe(() => {
return this._users$;
});
} else {
return this._users$;
}
}
_loadUsers() {
let _users$ = this.http.get(`${this._context}/users/`);
_users$.subscribe((users: User[]) => {
this._users$.next(Object.assign([], users));
});
}
_getUsersState(): User[] {
return this._users$.getValue();
}
edit yout component logic like this:
this.userService.usersChanged
.subscribe((users: any) => {
if(!!users){
console.log(users);
} else {
console.log("No user found!");
}
});
It's a good practise to have a variable that is an observable of your private behaviorSubject. So you just subscribe to it and whenever its state change, it'll emit.
Solution 2:[2]
getUsers method should return a observable and it's not good practice to subscribe observable in service. If you want to maintain state of users then use a singleton service. Declare property in service like this:
public users: Users[] = [];
private getUsers(): Observable<Users[]> {
if (!this.users.length) {
return this.http.get(`${this._context}/users/`);
}
return Observable.of(this.users);
}
In your component
this.userService.getUsers().subscribe((users: User[]) => {
this.userService.users = users; // (or users.slice(0)
console.log(users);
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jacopo Sciampi |
| Solution 2 | Sandip Jaiswal |
