Browse Source

fix(admin-ui): Fix back/forward nav issues with data table filters

Michael Bromley 2 years ago
parent
commit
58cb5a591d

+ 13 - 3
packages/admin-ui/src/lib/core/src/common/base-list.component.ts

@@ -1,4 +1,4 @@
-import { Directive, inject, OnDestroy, OnInit } from '@angular/core';
+import { DestroyRef, Directive, inject, OnDestroy, OnInit } from '@angular/core';
 import { FormControl } from '@angular/forms';
 import { ActivatedRoute, QueryParamsHandling, Router } from '@angular/router';
 import { ResultOf, TypedDocumentNode, VariablesOf } from '@graphql-typed-document-node/core';
@@ -212,8 +212,14 @@ export class TypedBaseListComponent<
     protected router = inject(Router);
     protected serverConfigService = inject(ServerConfigService);
     private refreshStreams: Array<Observable<any>> = [];
+    private collections: Array<DataTableFilterCollection | DataTableSortCollection<any>> = [];
     constructor() {
         super(inject(Router), inject(ActivatedRoute));
+
+        const destroyRef = inject(DestroyRef);
+        destroyRef.onDestroy(() => {
+            this.collections.forEach(c => c.destroy());
+        });
     }
 
     protected configure(config: {
@@ -241,11 +247,15 @@ export class TypedBaseListComponent<
     }
 
     createFilterCollection(): DataTableFilterCollection<NonNullable<NonNullable<Vars['options']>['filter']>> {
-        return new DataTableFilterCollection<NonNullable<Vars['options']['filter']>>(this.router);
+        const collection = new DataTableFilterCollection<NonNullable<Vars['options']['filter']>>(this.router);
+        this.collections.push(collection);
+        return collection;
     }
 
     createSortCollection(): DataTableSortCollection<NonNullable<NonNullable<Vars['options']>['sort']>> {
-        return new DataTableSortCollection<NonNullable<Vars['options']['sort']>>(this.router);
+        const collection = new DataTableSortCollection<NonNullable<Vars['options']['sort']>>(this.router);
+        this.collections.push(collection);
+        return collection;
     }
 
     setLanguage(code: LanguageCode) {

+ 14 - 2
packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter-collection.ts

@@ -4,7 +4,7 @@ import { CustomFieldType } from '@vendure/common/lib/shared-types';
 import { assertNever } from '@vendure/common/lib/shared-utils';
 import extend from 'just-extend';
 import { Subject } from 'rxjs';
-import { debounceTime, distinctUntilChanged, map, startWith } from 'rxjs/operators';
+import { debounceTime, distinctUntilChanged, map, startWith, takeUntil } from 'rxjs/operators';
 import {
     CustomFieldConfig,
     DateOperators,
@@ -28,6 +28,7 @@ import {
 
 export class FilterWithValue<Type extends DataTableFilterType = DataTableFilterType> {
     private onUpdateFns = new Set<(value: DataTableFilterValue<Type>) => void>();
+
     constructor(
         public readonly filter: DataTableFilter<any, Type>,
         public value: DataTableFilterValue<Type>,
@@ -85,6 +86,7 @@ export class DataTableFilterCollection<FilterInput extends Record<string, any> =
     #connectedToRouter = false;
     valueChanges = this.#valueChanges$.asObservable().pipe(debounceTime(10));
     readonly #filtersQueryParamName = 'filters';
+    private readonly destroy$ = new Subject<void>();
 
     constructor(private router: Router) {}
 
@@ -96,6 +98,11 @@ export class DataTableFilterCollection<FilterInput extends Record<string, any> =
         return this.#activeFilters;
     }
 
+    destroy() {
+        this.destroy$.next();
+        this.destroy$.complete();
+    }
+
     addFilter<FilterType extends DataTableFilterType>(
         config: DataTableFilterOptions<FilterInput, FilterType>,
     ): DataTableFilterCollection<FilterInput> {
@@ -218,7 +225,11 @@ export class DataTableFilterCollection<FilterInput extends Record<string, any> =
     }
 
     connectToRoute(route: ActivatedRoute) {
-        this.valueChanges.subscribe(() => {
+        this.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(val => {
+            const currentFilters = route.snapshot.queryParamMap.get(this.#filtersQueryParamName);
+            if (val.length === 0 && !currentFilters) {
+                return;
+            }
             this.router.navigate(['./'], {
                 queryParams: { [this.#filtersQueryParamName]: this.serialize(), page: 1 },
                 relativeTo: route,
@@ -230,6 +241,7 @@ export class DataTableFilterCollection<FilterInput extends Record<string, any> =
                 map(params => params.get(this.#filtersQueryParamName)),
                 distinctUntilChanged(),
                 startWith(route.snapshot.queryParamMap.get(this.#filtersQueryParamName) ?? ''),
+                takeUntil(this.destroy$),
             )
             .subscribe(value => {
                 this.#activeFilters = [];

+ 8 - 1
packages/admin-ui/src/lib/core/src/providers/data-table/data-table-sort-collection.ts

@@ -2,6 +2,7 @@ import { ActivatedRoute, Router } from '@angular/router';
 import { CustomFieldType } from '@vendure/common/lib/shared-types';
 import { assertNever } from '@vendure/common/lib/shared-utils';
 import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
 import { CustomFieldConfig } from '../../common/generated-types';
 import { DataTableSort, DataTableSortOptions, DataTableSortOrder } from './data-table-sort';
 
@@ -15,6 +16,7 @@ export class DataTableSortCollection<
     valueChanges = this.#valueChanges$.asObservable();
     readonly #sortQueryParamName = 'sort';
     #defaultSort: { name: keyof SortInput; sortOrder: DataTableSortOrder } | undefined;
+    private readonly destroy$ = new Subject<void>();
 
     constructor(private router: Router) {}
 
@@ -22,6 +24,11 @@ export class DataTableSortCollection<
         return this.#sorts.length;
     }
 
+    destroy() {
+        this.destroy$.next();
+        this.destroy$.complete();
+    }
+
     addSort<Name extends keyof SortInput>(
         config: DataTableSortOptions<SortInput, Name>,
     ): DataTableSortCollection<SortInput, [...Names, Name]> {
@@ -80,7 +87,7 @@ export class DataTableSortCollection<
     }
 
     connectToRoute(route: ActivatedRoute) {
-        this.valueChanges.subscribe(value => {
+        this.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(() => {
             this.router.navigate(['./'], {
                 queryParams: { [this.#sortQueryParamName]: this.serialize() },
                 relativeTo: route,