#1460 Remember Scroll Position, Implementing Dynamic Logic Start

This commit is contained in:
Nino Righi
2021-02-23 14:21:11 +01:00
committed by Lorenz Hilpert
parent a1708ca5a5
commit f4056d33a6
5 changed files with 104 additions and 25 deletions

View File

@@ -1,15 +1,14 @@
import { Component, ChangeDetectionStrategy, OnInit, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Component, ChangeDetectionStrategy, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core';
import { ActivatedRoute, NavigationStart, Router } from '@angular/router';
import { ApplicationService, ProcessService } from '@core/application';
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
import { CartService } from '@domain/cart';
import { CheckoutService } from '@domain/checkout';
import { AddressHelper, AssignedPayerHelper, CrmCustomerService } from '@domain/crm';
import { CustomerDTO, KeyValueDTOOfStringAndString } from '@swagger/crm';
import { UiDebugModalComponent, UiModalService } from '@ui/modal';
import { isArray } from '@utils/common';
import { UiModalService } from '@ui/modal';
import { ShippingAddressHelper } from 'apps/domain/crm/src/lib/helpers/shipping-address.helper';
import { Observable } from 'rxjs';
import { Observable, Subscription } from 'rxjs';
import { first, map, shareReplay, switchMap, tap } from 'rxjs/operators';
import { CantAddCustomerToCartModalComponent } from '../modals/cant-add-customer-to-cart-modal/cant-add-customer-to-cart.component';
import { CantAddCustomerToCartData } from '../modals/cant-add-customer-to-cart-modal/cant-add-customer-to-cart.data';
@@ -20,7 +19,7 @@ import { CantAddCustomerToCartData } from '../modals/cant-add-customer-to-cart-m
styleUrls: ['customer-details.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomerDetailsComponent implements OnInit {
export class CustomerDetailsComponent implements OnInit, OnDestroy {
customerId$: Observable<number>;
customer$: Observable<CustomerDTO>;
@@ -40,6 +39,8 @@ export class CustomerDetailsComponent implements OnInit {
private currentBreadcrumb: Breadcrumb;
scrollSubscription: Subscription;
constructor(
private activatedRoute: ActivatedRoute,
private customerDetailsService: CrmCustomerService,
@@ -105,6 +106,15 @@ export class CustomerDetailsComponent implements OnInit {
)
);
this.scrollSubscription = this.router.events.subscribe((events) => {
if (events instanceof NavigationStart) {
if (!events?.url.includes('/customer/search') && !events?.url.includes('query')) {
// Scrollposition im sessionStorage löschen wenn nicht zur suche zurück navigiert wird
sessionStorage.removeItem('scrollPos');
}
}
});
this.isB2b$ = this.customerType$.pipe(map((type) => type === 'b2b'));
this.isWebshopOrGuest$ = this.customerType$.pipe(map((type) => type === 'webshop' || type === 'guest'));
@@ -114,6 +124,12 @@ export class CustomerDetailsComponent implements OnInit {
this.createBreadcrumb();
}
ngOnDestroy() {
if (!!this.scrollSubscription) {
this.scrollSubscription.unsubscribe();
}
}
async createBreadcrumb() {
const customerId = await this.customerId$.pipe(first()).toPromise();

View File

@@ -6,19 +6,7 @@ import { CrmCustomerService } from '@domain/crm';
import { PagedResult } from '@domain/defs';
import { AutocompleteDTO, CustomerInfoDTO } from '@swagger/crm';
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
import {
catchError,
debounceTime,
distinctUntilChanged,
filter,
first,
map,
shareReplay,
switchMap,
take,
takeUntil,
tap,
} from 'rxjs/operators';
import { catchError, debounceTime, distinctUntilChanged, filter, map, shareReplay, switchMap, take, takeUntil, tap } from 'rxjs/operators';
import { CustomerSearchType, QueryFilter, ResultState } from './defs';
import { cloneFilter, Filter, UiFilterMappingService } from '@ui/filter';
import { NativeContainerService } from 'native-container';
@@ -59,6 +47,8 @@ export abstract class CustomerSearch implements OnInit, OnDestroy {
result: [],
});
searchCompleted = new Subject();
public searchState$ = new BehaviorSubject<ResultState>('init');
get searchState(): ResultState {
@@ -317,6 +307,8 @@ export abstract class CustomerSearch implements OnInit, OnDestroy {
if (hits > 0) {
this.filterActive$.next(false);
}
this.searchCompleted.next();
});
}
}

View File

@@ -29,6 +29,7 @@ export class CustomerSearchMainComponent implements OnInit, OnDestroy {
ngOnInit() {
this.detectDevice();
this.initBreadcrumb();
sessionStorage.removeItem('scrollPos');
}
initBreadcrumb() {

View File

@@ -1,9 +1,9 @@
<div class="scroll-container" *ngIf="search.searchState$ | async as searchState">
<div #scrollContainer class="scroll-container" *ngIf="search.searchState$ | async as searchState">
<a
[class.last]="last"
[class.load]="searchState === 'fetching'"
[routerLink]="['/customer', customer.id]"
*ngFor="let customer of (search.searchResult$ | async)?.result; let last = last"
*ngFor="let customer of customers$ | async; let last = last"
uiIsInViewport
[options]="viewportEnterOptions"
(viewportEntered)="checkIfReload($event)"

View File

@@ -1,8 +1,11 @@
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { NavigationStart, Router } from '@angular/router';
import { ApplicationService } from '@core/application';
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
import { filter, take } from 'rxjs/operators';
import { Observable, Subscription } from 'rxjs';
import { filter, map, take } from 'rxjs/operators';
import { CustomerSearch } from '../customer-search.service';
import { CustomerSearchType } from '../defs';
@Component({
selector: 'page-customer-search-result',
@@ -10,19 +13,80 @@ import { CustomerSearch } from '../customer-search.service';
styleUrls: ['./search-results.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomerSearchResultComponent implements OnInit, OnDestroy {
export class CustomerSearchResultComponent implements OnInit, OnDestroy, AfterViewInit {
@ViewChild('scrollContainer', { static: false }) scrollContainer: ElementRef<HTMLDivElement>;
private _breadcrumb: Breadcrumb;
customers$: Observable<CustomerSearchType[]>;
scrollSubscription: Subscription;
onLoadSubscription: Subscription;
protected readonly viewportEnterOptions: IntersectionObserverInit = {
threshold: 0.75,
};
constructor(private application: ApplicationService, private breadcrumb: BreadcrumbService, public search: CustomerSearch) {}
constructor(
private application: ApplicationService,
private breadcrumb: BreadcrumbService,
public search: CustomerSearch,
private router: Router
) {}
ngOnInit() {
this.customers$ = this.search.searchResult$.pipe(
map((response) => {
// console.log(response);
return response.result;
})
);
// Safe current scroll position if navigating to Customer Details
this.scrollSubscription = this.router.events.subscribe((events) => {
if (events instanceof NavigationStart) {
const customerId = Number.parseInt(events.url.replace(/\D/g, ''), 10);
if (events?.url === `/customer/${customerId}`) {
// Safe Scrollposition inside sessionStorage
sessionStorage.setItem('scrollPos', `${this.scrollContainer.nativeElement.scrollTop}`);
// - TESTING -
// Safe Loaded customers
// --> SAFE EDITED DATA TO LOADED CUSTOMERS ASWELL !!
// this.search.searchResult$.subscribe((res) => {
// console.log(res.result);
// sessionStorage.setItem('preloadedCustomers', JSON.stringify(res.result));
// });
console.log(this.search.searchResult$.value.result);
// sessionStorage.setItem('preloadedCustomers', JSON.stringify(this.search.searchResult$.value.result));
} else {
sessionStorage.removeItem('scrollPos');
// sessionStorage.removeItem('preloadedCustomers');
}
}
});
this.initBreadcrumb();
}
ngAfterViewInit() {
// Start scrolling to last remembered position
this.scrollContainer.nativeElement.scrollTo(0, Number(sessionStorage.getItem('scrollPos')));
// ### SHOULD BE REMOVED IF CONTENT GETS PRELOADED ###
// If content needs to be loaded, invoke the scroll again
this.onLoadSubscription = this.search.searchCompleted.subscribe(() => {
const container = this.scrollContainer.nativeElement.scrollTop;
const storage = Number(sessionStorage.getItem('scrollPos'));
if (container <= storage) {
// Scroll to content
this.scrollContainer.nativeElement.scrollTo(0, storage);
} else if (storage <= 1100) {
// Stop scrolling if needed content is loaded without loading more items
this.onLoadSubscription.unsubscribe();
} else {
// Jump to content after items loaded and stop scrolling
this.scrollContainer.nativeElement.scrollTo(0, storage);
this.onLoadSubscription.unsubscribe();
}
});
}
async initBreadcrumb() {
await this.search.filtersLoaded$
.pipe(
@@ -55,6 +119,12 @@ export class CustomerSearchResultComponent implements OnInit, OnDestroy {
ngOnDestroy() {
this.search.searchState$.next('init');
if (!!this.scrollSubscription) {
this.scrollSubscription.unsubscribe();
}
if (!!this.onLoadSubscription) {
this.onLoadSubscription.unsubscribe();
}
}
checkIfReload(target: HTMLElement): void {