我有一个简单的项目,该项目从JSON文件获取用户数据,它将在另一个页面中显示单个用户的数据。 我的“老师”告诉我,我必须使用2个服务来处理用户数据,一个服务用于处理http请求,另一个服务则采用可观察的并执行CRUD操作。
这是HTTP服务
user-Http.service.ts
constructor(private http:HttpClient) { }
getBooks() {
return this.http.get<User[]>(environment.userUrl);
}
这是用户服务
user.service.ts
users: User[];
user: User[] = new User;
constructor(private userHttp: UsersHttpService) {
userHttp.getBooks().subscribe(res => {
this.users = res;
})
}
//...
getUser(id: number) {
this.userHttp.getBooks().subscribe(res => {
if (res != null) {
this.users = res;
console.log(this.users.find(user => user.id == id))
this.user = this.users.find(user => user.id == id);
console.log('Return ', this.user)
return this.user;
}
});
}
//...
但是当我在用户信息组件中调用getUser函数时,控制台将返回此错误
错误TypeError:无法读取未定义的属性“ find” 在UserService.getUser(user.service.ts:23)
这是用户信息组件
user-info.component.ts
public user: User
constructor(private route: ActivatedRoute, private _userService: UserService) { }
ngOnInit(): void {
this.route.params.subscribe(
p => {
this.user = this._userService.getUser(p.id);
}
)
}
user-info.component.html
{{user | json}}
在许多控制台日志之后,我发现getUser函数在订阅结束之前已执行,因此,它执行对未定义数组的查找并抛出此错误。 我该如何解决?
答案 0 :(得分:1)
我将userHttps.getBooks()和getUser()结合起来
constructor(private userHttp: UsersHttpService) {}
getUser(id: number): User {
userHttp.getBooks().subscribe(res => {
if (res != null) {
this.users = res;
return this.users.find(user => user.id == id);;
}
return null;
});
}
答案 1 :(得分:0)
您可以使用switchMap之类的内容来嵌套订阅。
这样,您将不会遇到现在面临的问题。
此外,尝试根据您的需求浏览地图,haustMap,concatMap和MergeMap。
我已经使用过地图,因为无法观察到返回,请找到stackblitz
答案 2 :(得分:0)
在HTTP调用获取用户列表之前,有角调用getUser()
。要立即修复,请初始化users数组:
users: User[] = [];
或者在getUser()
getUser(id: number) {
return this.users ? this.users.find(user => user.id == id) : null;
}
答案 3 :(得分:0)
您可以使用subject来确保仅在从服务中检索到数据后才能获取数据。
您的UserHttpService类未更改,但是在UserService类中添加了组件将订阅的主题
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Subject } from 'rxjs';
import { UserHttpService } from './user-http.service';
import { take } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class UserService {
private user: User;
public userSelected = new Subject<boolean>();
constructor(private userHttpServ: UserHttpService) {
}
getUserById(id: number) {
this.userHttpServ.getBooks()
.pipe(take(1))
.subscribe((res => {
this.user = res.results.find(u => u.id == id);
if (this.people !== undefined) {
this.userSelected.next(true);
} else {
this.userSelected.next(false);
}
});
}
getUser() {
return {...this.user };
}
}
在组件中,您预订了userSelected主题。您调用getUserById,当找到用户时,主题将发出true,并且您的订阅将获取用户数据。
export class UserInfoComponent {
public user: User;
private userSub: Subscription;
constructor(private userServ: UserService) {
this.userSub = this.userServ.userSelected.subscribe(res => {
if (res) {
this.user = this.userServ.getUser();
}
});
}
getUserById(id: number) {
this.userServ.getUser(id);
}
...
}
别忘了取消ngOnDestroy上的userSub订阅,以避免内存泄漏。