我正在用angular 12和rxjs编写一个类似电子商务的应用程序。
我创建了一个类别服务,从服务器中获取graphql类别并解析它们,因此它将很容易在网站的其余部分获得。
我遇到的问题是,如果用户立即进入一个使用类别服务的页面,那么它返回一个空响应,因为graphql还没有返回值。
所以我决定创建一个isinitialized可观察对象,并在它完成时将其设置为true,这样其他函数就知道它是可操作的
@Injectable({
providedIn: 'root'
})
export class ProductCategoriesService {
adminQueryProductCategories=this.gql.adminQueryProductCategories();
isInitialized: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
constructor(private gql: GraphqlService) {
this.adminQueryProductCategories.valueChanges.subscribe(({data})=>{
this.categories=data.adminQueryProductCategories;
this.parseCategoryTree(this.categories);
this.isInitialized.next(true);
});
}
现在这个函数从产品类别的可观察对象中获取数据:
getCategoryTitleByLabel(label: string): Observable<ProductCategory[]> {
return this.productCategories$.pipe(map((pc: ProductCategory[]) => pc.filter(p => p.category_label === label)));
}
我不知道如何实现这个可观察对象应该只有在isInitialized为真之后才执行
任何想法?
谢谢
一般来说,当用户浏览一个类别页面时,我想检查该类别是否存在,如果不存在,则将他路由到主页面。所以在第一次加载时,由于graphql请求没有完成,他总是被路由到主页面。
这是代码:
ngOnInit(): void {
this.route.params.subscribe(params => {
this.label = params['category'];
this.pcService.getCategoryTitleByLabel(this.label).subscribe((data)=>{
if (data.length !== 1) {
this.router.navigate(['/']).finally(()=>{
//TODO: popup of some sort ?
});
} else {
** update2 **
这是productCategories$
的实现:
private productCategories = new BehaviorSubject<ProductCategory[]>([]);
get productCategories$(): Observable<ProductCategory[]> {
return this.productCategories;
}
**解决方案**
非常感谢你们的帮助。解决方案是简单地使用ReplaySubject
,而不是@BizzyBob建议的BehaviorSubject
。所以
不是
private productCategories = new BehaviorSubject<ProductCategory[]>([]);
get productCategories$(): Observable<ProductCategory[]> {
return this.productCategories;
}
我
productCategories$ = new ReplaySubject<ProductCategory[]>();
就是这样。问题解决:)get category by label函数保持不变:
getCategoryTitleByLabel(label: string): Observable<ProductCategory[]> {
return this.productCategories$.pipe(map((pc: ProductCategory[]) => pc.filter(p => p.category_label === label)));
}
您可以通过使用filter
和switchMap
来实现您正在寻找的内容,如下所示:
getCategoryTitleByLabel(label: string): Observable<ProductCategory[]> {
return this.isInitialized$.pipe(
filter(isInitialized => !!isInitialized),
switchMap(() => this.productCategories$),
map(pc => pc.filter(p => p.category_label === label))
);
}
但对我来说,真正的问题似乎是这句话:
它返回一个空响应,因为图形还没有返回值
this.productCategories$
应该只发出有意义的数据,而不是"空响应"。除非"空";响应是有意义的,这似乎不是,它们应该在流的早期被过滤掉。如果是这种情况,您就不需要引入isInitialized$
属性。
尝试如下:
getCategoryTitleByLabel(label: string): Observable<ProductCategory[]> {
return combineLatest({
pc: this.productCategories$,
init: this.isInitialized
}).pipe(
filter(({ init }) => !!init),
map(({ pc }) => pc.filter(p => p.category_label === label))
);
}
我的建议是订阅BehaviorSubject observable
你可以获取可观察对象的结果并执行一个操作:
this.isInitialized.subscribe((res) => {
if (res === true)
{
// do something, maybe set a flag etc.
}
});