LP1899406 Basket view allows for (de)select all operation user/berick/lp1899406-staff-cat-view-basket-selection-v2
authorBill Erickson <berickxx@gmail.com>
Wed, 10 Feb 2021 20:15:13 +0000 (15:15 -0500)
committerBill Erickson <berickxx@gmail.com>
Wed, 10 Feb 2021 20:15:15 +0000 (15:15 -0500)
Within the staff client catalog basket view page, users can now select
and deselect all items in the basket for basket actions, without otherwise
affecting the contents of the basket.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/share/catalog/catalog.service.ts
Open-ILS/src/eg2/src/app/staff/catalog/basket-selection.service.ts
Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.html
Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.ts

index af996c2..36c3ead 100644 (file)
@@ -99,11 +99,14 @@ export class CatalogService {
 
         return this.basket.getRecordIds().then(ids => {
 
+            const pageIds =
+                ids.slice(ctx.pager.offset, ctx.pager.limit + ctx.pager.offset);
+
             // Map our list of IDs into a search results object
             // the search context can understand.
             const result = {
                 count: ids.length,
-                ids: ids.map(id => [id])
+                ids: pageIds.map(id => [id])
             };
 
             this.applyResultData(ctx, result);
index 892de60..ce9001e 100644 (file)
@@ -13,6 +13,8 @@ export class BasketSelectionService {
 
     idList: number[];
 
+    onChange: EventEmitter<number[]> = new EventEmitter<number[]>();
+
     constructor(private basket: BasketService) {
         this.idList = [];
     }
@@ -35,6 +37,7 @@ export class BasketSelectionService {
 
     setRecordIds(ids: number[]): Promise<number[]> {
         this.idList = ids;
+        this.onChange.emit(this.idList);
         return Promise.resolve(this.idList);
     }
 
index eb22bd8..0501c5f 100644 (file)
@@ -29,7 +29,7 @@ export class ResultRecordComponent implements OnInit, OnDestroy {
 
     searchContext: CatalogSearchContext;
     isRecordSelected: boolean;
-    basketSub: Subscription;
+    selectorSub: Subscription;
     hasCourse = false;
     courses: any[] = [];
 
@@ -49,22 +49,24 @@ export class ResultRecordComponent implements OnInit, OnDestroy {
     ngOnInit() {
         this.searchContext = this.staffCat.searchContext;
         this.loadCourseInformation(this.summary.id);
-        this.isRecordSelected = this.basket.hasRecordId(this.summary.id);
-
-        // Watch for basket changes caused by other components
-        this.basketSub = this.basket.onChange.subscribe(() => {
-            this.isRecordSelected = this.basket.hasRecordId(this.summary.id);
-        });
 
         if (this.searchContext.showBasket) {
             this.recordSelector = this.basketSelect;
         } else {
             this.recordSelector = this.basket;
         }
+
+        this.isRecordSelected = this.recordSelector.hasRecordId(this.summary.id);
+
+        // Watch for basket changes caused by other components
+        this.selectorSub = this.recordSelector.onChange.subscribe(() => {
+            this.isRecordSelected =
+                this.recordSelector.hasRecordId(this.summary.id);
+        });
     }
 
     ngOnDestroy() {
-        this.basketSub.unsubscribe();
+        this.selectorSub.unsubscribe();
     }
 
     loadCourseInformation(recordId) {
index ac78bba..094d9ef 100644 (file)
       <h3 i18n>Basket View</h3>
     </div>
     <div class="col-lg-2">
+      <label class="checkbox" *ngIf="searchContext.showBasket">
+        <input type='checkbox' [(ngModel)]="allRecsSelected" 
+            (change)="toggleAllRecsSelected()"/>
+        <span class="pl-1" i18n>Select All</span>
+      </label>
       <label class="checkbox" *ngIf="!searchContext.showBasket">
         <input type='checkbox' [(ngModel)]="allRecsSelected" 
             (change)="toggleAllRecsSelected()"/>
index 2cc6604..c9a1edc 100644 (file)
@@ -29,6 +29,8 @@ export class ResultsComponent implements OnInit, OnDestroy {
     searchSub: Subscription;
     routeSub: Subscription;
     basketSub: Subscription;
+    basketSelectSub: Subscription;
+    showingBasket = false;
 
     recordSelector: BasketService |  BasketSelectionService;
 
@@ -53,16 +55,26 @@ export class ResultsComponent implements OnInit, OnDestroy {
         // searches.
         //
         // This will also fire on page load.
-        this.routeSub =
-            this.route.queryParamMap.subscribe((params: ParamMap) => {
-
-              // TODO: Angular docs suggest using switchMap(), but
-              // it's not firing for some reason.  Also, could avoid
-              // firing unnecessary searches when a param unrelated to
-              // searching is changed by .map()'ing out only the desired
-              // params and running through .distinctUntilChanged(), but
-              // .map() is not firing either.  I'm missing something.
-              this.searchByUrl(params);
+        this.routeSub = this.route.queryParamMap.subscribe((params: ParamMap) => {
+
+            // TODO: Angular docs suggest using switchMap(), but
+            // it's not firing for some reason.  Also, could avoid
+            // firing unnecessary searches when a param unrelated to
+            // searching is changed by .map()'ing out only the desired
+            // params and running through .distinctUntilChanged(), but
+            // .map() is not firing either.  I'm missing something.
+            this.searchByUrl(params);
+
+            if (this.searchContext.showBasket) {
+                if (!this.showingBasket) {
+                    // Only init the basket selector when navigating
+                    // to the basket view from a non-basket view.
+                    this.basketSelect.init();
+                    this.showingBasket = true;
+                }
+            } else {
+                this.showingBasket = false;
+            }
         });
 
         // After each completed search, update the record selector.
@@ -73,9 +85,11 @@ export class ResultsComponent implements OnInit, OnDestroy {
         this.basketSub = this.basket.onChange.subscribe(
             () => this.applyRecordSelection());
 
+        this.basketSelectSub = this.basketSelect.onChange.subscribe(
+            () => this.applyRecordSelection());
+
         if (this.searchContext.showBasket) {
             this.recordSelector = this.basketSelect;
-            this.basketSelect.init();
         } else {
             this.recordSelector = this.basket;
         }
@@ -86,13 +100,16 @@ export class ResultsComponent implements OnInit, OnDestroy {
             this.routeSub.unsubscribe();
             this.searchSub.unsubscribe();
             this.basketSub.unsubscribe();
+            this.basketSelectSub.unsubscribe();
         }
     }
 
     // Apply the select-all checkbox when all visible records
     // are selected.
     applyRecordSelection() {
-        const ids = this.searchContext.currentResultIds();
+        const ids = this.showingBasket ? this.basket.idList :
+            this.searchContext.currentResultIds();
+
         let allChecked = true;
         ids.forEach(id => {
             if (!this.recordSelector.hasRecordId(id)) {
@@ -129,12 +146,23 @@ export class ResultsComponent implements OnInit, OnDestroy {
     }
 
     toggleAllRecsSelected() {
-        const ids = this.searchContext.currentResultIds();
 
-        if (this.allRecsSelected) {
-            this.recordSelector.addRecordIds(ids);
+        if (this.showingBasket) {
+            if (this.allRecsSelected) {
+                this.basketSelect.init();
+            } else {
+                this.basketSelect.removeAllRecordIds();
+            }
+
         } else {
-            this.recordSelector.removeRecordIds(ids);
+
+            const ids = this.searchContext.currentResultIds();
+
+            if (this.allRecsSelected) {
+                this.recordSelector.addRecordIds(ids);
+            } else {
+                this.recordSelector.removeRecordIds(ids);
+            }
         }
     }
 }