I have a real-time updating list of orders that is scrollable. This is the main component, where the list gets updated every 2 minutes with the following setup:
ngOnInit(): void {
this.internalError = false;
this.subscription = timer(0, 120 * 1000).pipe(
switchMap(() => this.shopService.getPreferencesAsObservable()),
filter(preferences => !!preferences), // emit only if `preferences` is defined and truthy
tap(() => {
this.isDeliverySlotsActive = this.shopService.isDeliverySlotsActive();
}),
switchMap(() =>
forkJoin([
this.getInitialPendingOrders(true),
this.getInitialPendingOrders(false),
this.getInitialDeliveredOrders(true),
this.getInitialDeliveredOrders(false),
this.getInitialCancelledOrders(true),
this.getInitialCancelledOrders(false)
]
)
)
).subscribe(res => {
/* pending slots */
this.loadedPendingSlotsOrders = [...res[0]["results"]];
this.pendingSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedPendingSlotsOrders, true);
/* pending no slots */
this.loadedPendingNoSlotsOrders = this.ordersService.filterOrders(res[1]["results"], OrderStatus.PENDING, false);
this.loadedProcessedNoSlotsOrders = this.ordersService.filterOrders(res[1]["results"], OrderStatus.PROCESSED, false);
this.loadedPendingNoSlotsOrders = [...this.loadedPendingNoSlotsOrders, ...this.loadedProcessedNoSlotsOrders];
this.pendingNoSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedPendingNoSlotsOrders, false);
/* delivered slots */
this.loadedDeliveredSlotsOrders = [...res[2]["results"]];
this.deliveredSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedDeliveredSlotsOrders, true);
/* delivered no slots */
this.loadedDeliveredNoSlotsOrders = this.ordersService.filterOrders(res[3]["results"], OrderStatus.DELIVERED, false);
this.deliveredNoSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedDeliveredNoSlotsOrders, false);
/* cancelled slots*/
this.loadedCancelledSlotsOrders = [...res[4]["results"]];
this.cancelledSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedCancelledSlotsOrders, true);
/* cancelled no slots */
this.loadedCancelledNoSlotsOrders = this.ordersService.filterOrders(res[5]["results"], OrderStatus.CANCELLED, false);
this.cancelledNoSlotsOrderTimelines = this.ordersService.createTimelines(this.loadedCancelledNoSlotsOrders, false);
/* data is ready, we can stop showing spinner */
this.isLoaded = Promise.resolve(true);
});
}
getInitialPendingOrders(hasSlots: boolean){
return this.apiService.fetchShopOrders("status=PENDING&status=FULFILLED" + (hasSlots ? "&only_slots=true" : ''));
}
getInitialDeliveredOrders(hasSlots: boolean){
return this.apiService.fetchShopOrders("status=DELIVERED" + (hasSlots ? "&only_slots=true" : ''));
}
getInitialCancelledOrders(hasSlots: boolean){
return this.apiService.fetchShopOrders("status=CANCELLED" + (hasSlots ? "&only_slots=true" : ''));
}
Moreover, the component hierarchy is as follows:
OrdersComponent (prepare data to send to children) -> OrdersListComponent (*ngFor of sections) -> OrdersListSectionComponent (*ngFor of orders) -> OrdersListItemComponent (single order)
Here you can see how the list looks (it's an inner scrollable div):
https://i.sstatic.net/4wHos.png
The CSS for the scrollable div:
.scrollable {
min-height: 10vh;
max-height: 50vh;
overflow: auto;
background:
linear-gradient(white 33%, rgba(179,86,216, 0)),
linear-gradient(rgba(179,86,216, 0), white 66%) 0 100%,
radial-gradient(farthest-side at 50% 0, rgba(34,34,34, 0.5), rgba(0,0,0,0)),
radial-gradient(farthest-side at 50% 100%, rgba(34,34,34, 0.5), rgba(0,0,0,0)) 0 100%;
background-repeat: no-repeat;
background-attachment: local, local, scroll, scroll;
background-size: 100% 1.5rem, 100% 1.5rem, 100% 0.5rem, 100% 0.5rem;
scroll-behavior: smooth;
}
The template for the OrdersListSectionComponent
:
<div *ngFor="let order of sectionOrders">
<app-orders-list-item
[order]="order"
[timeline]="timeline"
></app-orders-list-item>
<hr class="order-divider"/>
</div>
I have encountered an issue where the scroll of the list resets to the top whenever the timer triggers a refresh. This disrupts the user experience as it shouldn't reset the scroll position while the user is scrolling. Does anyone have a solution to prevent this unwanted scroll behavior?