英文:
Why does Angular route resolver only listen to the first value of my observable?
问题
我理解了,你想要关于Angular 15中路由解析器的帮助。你想确保解析器等待所有从可观察对象中发布的值。但目前你的解析器似乎只监听第一个值。
你可以尝试在解析器中使用 forkJoin
操作符,以确保等待所有产品都被获取后才继续。以下是一种可能的实现方式:
@Injectable()
export class ProductRouteGuardService {
constructor(private productService: ProductService) { }
resolve() {
return this.productService.getProducts().pipe(
take(1), // Make sure the observable completes after the first emission
toArray() // Collect all emitted values into an array
);
}
}
这里我们使用 take(1)
以确保在第一个值被发出后,可观察对象就会完成。然后使用 toArray()
来将所有值收集到一个数组中。
希望这对你有所帮助!如果你有任何其他问题,请随时提出。
英文:
I am working with Angular 15 and I am trying to use the routing resolver handler to prefetch products before loading a product-list component. This product-list component simply displays the products. I am very new to stackoverflow so I'll try my best to explain my problem.
I have 4 main actors:
> ProductListComponent
> app-routing module
> ProductRouteGuard
> ProductService
The app-routing-module
is my router, routing to the ProductListComponent
, when the url "/products" is requested but right before loading this component, my router calls the ProductRouteGuard
resolver to prefetch products before loading my ProductListComponent
My router :
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
{
path: 'products', component: ProductListComponent, resolve: {products: ProductRouteGuardService}
}
<!-- end snippet -->
And then my ProductRouteGuard
resolver asks my ProductService to get the products list:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
@Injectable()
export class ProductRouteGuardService{
constructor(private productService : ProductService) { }
resolve(){
return this.productService.getProducts().pipe(
map(product=> product)
);
}
<!-- end snippet -->
My ProductService
:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
@Injectable()
export class ProductService{
products = [...]; // array of products
getProducts(){
let products$ = from(this.products); // observable of products to simulate an api response
return products$;
}
<!-- end snippet -->
Eventually my ProductListComponent
gets the data by asking the router resolver :
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
export class ProductListComponent implements OnInit{
products : any; // my component local array to display products
constructor(private route : ActivatedRoute){}
ngOnInit(): void {
this.products = [this.route.snapshot.data['products']];
console.log(this.products)
}
}
<!-- end snippet -->
So when I run this code, I can see that only my first product is logged in the console meaning, in my opinion, the resolver is only listening the first value published by my observable. I know that in my Observable subscriber function, I could just do something like :
> observer.next(this.products);
But I really want the products all to be fetched one by one, and the resolver waiting for them to be all fetched.
My question is : How can I make the router resolver to listen to all the published values coming from my observable ?
答案1
得分: 1
尝试使用of([...])
操作符,而不是在服务内部使用from([...])
。
更多信息:stackoverflow.com/questions/42704552/of-vs-from-operator
需要注意的是,在传递类似数组的结构(包括字符串)时,of 和 from 之间的区别很重要:
Observable.of([1, 2, 3]).subscribe(x => console.log(x));
会一次性打印整个数组。另一方面,
Observable.from([1, 2, 3]).subscribe(x => console.log(x));
会逐个打印元素。对于字符串,行为相同,但在字符级别上。
如果你想解析多个值,你可以使用rxjs操作符将它们组合在一起,然后一次性解析:
@Injectable()
export class ProductService{
products = [...]; // 产品数组
categories = [...]; // 类别数组
getProducts(){
return of(this.products);
}
getCategories(){
return of(this.categories);
}
}
@Injectable()
export class ProductRouteGuardService{
constructor(private productService : ProductService) { }
resolve(){
return forkJoin([
this.productService.getProducts()
.pipe(map(products => products)),
this.productService.getCategories()
.pipe(map(categories => categories))]);
}
}
英文:
Try the of([...]) operator instead of the from([...]) in your simulation inside the service.
More info: https://stackoverflow.com/questions/42704552/of-vs-from-operator
> It is important to note the difference between of and from when passing an array-like structure (including strings):
>
> Observable.of([1, 2, 3]).subscribe(x => console.log(x));
would print the whole array at once.
>
> On the other hand,
> Observable.from([1, 2, 3]).subscribe(x => console.log(x));
prints the elements 1 by 1.
>
>For strings the behaviour is the same, but at character level.
If you want to resolve multiple values you can use rxjs operators to put them together and resolve once:
@Injectable()
export class ProductService{
products = [...]; // array of products
categories = [...]; // array of categories
getProducts(){
return of(this.products);
}
getCategories(){
return of(this.categories);
}
}
@Injectable()
export class ProductRouteGuardService{
constructor(private productService : ProductService) { }
resolve(){
return forkJoin([
this.productService.getProducts()
.pipe(map(products => products)),
this.productService.getCategories()
.pipe(map(categories => categories))]);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论