LP#1850547: eg-grid: disable filter controls while fetching data
authorGalen Charlton <gmc@equinoxinitiative.org>
Wed, 26 Feb 2020 19:49:31 +0000 (14:49 -0500)
committerBill Erickson <berickxx@gmail.com>
Thu, 3 Sep 2020 15:51:48 +0000 (11:51 -0400)
This avoids situations where the user who is quick on the mark
tries to set a filter condition but not see it take effect
when the original query returns results.

Sponsored-by: Evergreen Community Development Initiative
Sponsored-by: Georgia Public Library Service
Sponsored-by: Indiana State Library
Sponsored-by: C/W MARS
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Signed-off-by: Tiffany Little <tlittle@georgialibraries.org>
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/share/grid/grid-filter-control.component.html
Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.html
Open-ILS/src/eg2/src/app/share/grid/grid.ts

index 53155db..052de1c 100644 (file)
@@ -3,7 +3,9 @@
     <div *ngSwitchCase="'link'">
       <div class="input-group">
         <div ngbDropdown class="d-inline-block" autoClose="outside" placement="bottom-left" [ngClass]="{'eg-grid-col-is-filtered' : col.isFiltered}">
-          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button"><span class="material-icons mat-icon-in-button">filter_list</span></button>
+          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button" [disabled]="context.dataSource.requestingData">
+            <span class="material-icons mat-icon-in-button">filter_list</span>
+          </button>
           <div ngbDropdownMenu class="eg-grid-filter-menu">
             <div class="dropdown-item">
               <div style="padding-top: 2px;">
           </div>
         </div>
         <eg-combobox [asyncSupportsEmptyTermClick]="col.asyncSupportsEmptyTermClick" [idlClass]="col.idlFieldDef.class" (onChange)="applyLinkFilter($event, col)" 
+          [disabled]="col.filterInputDisabled || context.dataSource.requestingData"
           i18n-placeholder placeholder="Enter value to filter by"></eg-combobox>
       </div>
     </div>
     <div *ngSwitchCase="'bool'">
       <div class="input-group">
         <div ngbDropdown class="d-inline-block" autoClose="outside" placement="bottom-left" [ngClass]="{'eg-grid-col-is-filtered' : col.isFiltered}">
-          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button"><span class="material-icons mat-icon-in-button">filter_list</span></button>
+          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button" [disabled]="context.dataSource.requestingData">
+            <span class="material-icons mat-icon-in-button">filter_list</span>
+          </button>
           <div ngbDropdownMenu class="eg-grid-filter-menu">
             <div class="dropdown-item">
               <div style="padding-top: 2px;">
@@ -32,7 +37,8 @@
             </div>
           </div>
         </div>
-        <select class="custom-select" [(ngModel)]="col.filterValue" (change)="applyBooleanFilter(col)">
+        <select class="custom-select" [(ngModel)]="col.filterValue" (change)="applyBooleanFilter(col)"
+            [disabled]="col.filterInputDisabled || context.dataSource.requestingData">
           <option value="" i18n>Any</option>
           <option value="t" i18n>True</option>
           <option value="f" i18n>False</option>
@@ -42,7 +48,9 @@
     <div *ngSwitchCase="'text'">
       <div class="input-group">
         <div ngbDropdown class="d-inline-block" autoClose="outside" placement="bottom-left" [ngClass]="{'eg-grid-col-is-filtered' : col.isFiltered}">
-          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button"><span class="material-icons mat-icon-in-button">filter_list</span></button>
+          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button" [disabled]="context.dataSource.requestingData">
+            <span class="material-icons mat-icon-in-button">filter_list</span>
+          </button>
           <div ngbDropdownMenu class="eg-grid-filter-menu">
             <div class="dropdown-item">
               <label for="eg-filter-op-select-{{col.name}}" i18n>Operator</label>
           </div>
         </div>
         <input type="text" class="form-control" [(ngModel)]="col.filterValue" (keyup.enter)="applyFilter(col)" 
-          [disabled]="col.filterInputDisabled" i18n-placeholder placeholder="Enter value to filter by">
+          [disabled]="col.filterInputDisabled || context.dataSource.requestingData" i18n-placeholder placeholder="Enter value to filter by">
       </div>
     </div>
     <div *ngSwitchCase="'int'">
       <div class="input-group">
         <div ngbDropdown class="d-inline-block" autoClose="outside" placement="bottom-left" [ngClass]="{'eg-grid-col-is-filtered' : col.isFiltered}">
-          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button"><span class="material-icons mat-icon-in-button">filter_list</span></button>
+          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button" [disabled]="context.dataSource.requestingData">
+            <span class="material-icons mat-icon-in-button">filter_list</span>
+          </button>
           <div ngbDropdownMenu class="eg-grid-filter-menu">
             <div class="dropdown-item">
               <label for="eg-filter-op-select-{{col.name}}" i18n>Operator</label>
             </div>
           </div>
         </div>
-        <input type="number" min="0" step="1" class="form-control" [(ngModel)]="col.filterValue" (keyup.enter)="applyFilter(col)" [disabled]="col.filterInputDisabled">
+        <input type="number" min="0" step="1" class="form-control" [(ngModel)]="col.filterValue" (keyup.enter)="applyFilter(col)" [disabled]="col.filterInputDisabled || context.dataSource.requestingData">
       </div>
     </div>
     <div *ngSwitchCase="'id'">
       <div class="input-group">
         <div ngbDropdown class="d-inline-block" autoClose="outside" placement="bottom-left" [ngClass]="{'eg-grid-col-is-filtered' : col.isFiltered}">
-          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button"><span class="material-icons mat-icon-in-button">filter_list</span></button>
+          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button" [disabled]="context.dataSource.requestingData">
+            <span class="material-icons mat-icon-in-button">filter_list</span>
+          </button>
           <div ngbDropdownMenu class="eg-grid-filter-menu">
             <div class="dropdown-item">
               <label for="eg-filter-op-select-{{col.name}}" i18n>Operator</label>
             </div>
           </div>
         </div>
-        <input type="number" min="0" step="1" class="form-control" [(ngModel)]="col.filterValue" (keyup.enter)="applyFilter(col)" [disabled]="col.filterInputDisabled">
+        <input type="number" min="0" step="1" class="form-control" [(ngModel)]="col.filterValue" (keyup.enter)="applyFilter(col)" [disabled]="col.filterInputDisabled || context.dataSource.requestingData">
       </div>
     </div>
     <div *ngSwitchCase="'float'">
       <div class="input-group">
         <div ngbDropdown class="d-inline-block" autoClose="outside" placement="bottom-left" [ngClass]="{'eg-grid-col-is-filtered' : col.isFiltered}">
-          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button"><span class="material-icons mat-icon-in-button">filter_list</span></button>
+          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button" [disabled]="context.dataSource.requestingData">
+            <span class="material-icons mat-icon-in-button">filter_list</span>
+          </button>
           <div ngbDropdownMenu class="eg-grid-filter-menu">
             <div class="dropdown-item">
               <label for="eg-filter-op-select-{{col.name}}" i18n>Operator</label>
             </div>
           </div>
         </div>
-        <input type="number" class="form-control" [(ngModel)]="col.filterValue" (keyup.enter)="applyFilter(col)" [disabled]="col.filterInputDisabled">
+        <input type="number" class="form-control" [(ngModel)]="col.filterValue" (keyup.enter)="applyFilter(col)" [disabled]="col.filterInputDisabled || context.dataSource.requestingData">
       </div>
     </div>
     <div *ngSwitchCase="'money'">
       <div class="input-group">
         <div ngbDropdown class="d-inline-block" autoClose="outside" placement="bottom-left" [ngClass]="{'eg-grid-col-is-filtered' : col.isFiltered}">
-          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button"><span class="material-icons mat-icon-in-button">filter_list</span></button>
+          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button" [disabled]="context.dataSource.requestingData">
+            <span class="material-icons mat-icon-in-button">filter_list</span>
+          </button>
           <div ngbDropdownMenu class="eg-grid-filter-menu">
             <div class="dropdown-item">
               <label for="eg-filter-op-select-{{col.name}}" i18n>Operator</label>
             </div>
           </div>
         </div>
-        <input type="number" step="0.01" class="form-control" [(ngModel)]="col.filterValue" (keyup.enter)="applyFilter(col)" [disabled]="col.filterInputDisabled">
+        <input type="number" step="0.01" class="form-control" [(ngModel)]="col.filterValue" (keyup.enter)="applyFilter(col)" [disabled]="col.filterInputDisabled || context.dataSource.requestingData">
       </div>
     </div>
     <div *ngSwitchCase="'timestamp'">
       <div class="input-group">
         <div ngbDropdown class="d-inline-block" autoClose="outside" placement="bottom-left" [ngClass]="{'eg-grid-col-is-filtered' : col.isFiltered}">
-           <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button"><span class="material-icons mat-icon-in-button">filter_list</span></button>
-          <div ngbDropdownMenu class="eg-grid-filter-menu">
+            <div ngbDropdownMenu class="eg-grid-filter-menu">
+            <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button" [disabled]="context.dataSource.requestingData">
+              <span class="material-icons mat-icon-in-button">filter_list</span>
+            </button>
             <div class="dropdown-item">
               <label for="eg-filter-op-select-{{col.name}}" i18n>Operator</label>
               <select id="eg-filter-op-select-{{col.name}}" class="form-control" [(ngModel)]="col.filterOperator" (change)="operatorChanged(col)">
           </div>
         </div>
         <eg-date-select [initialYmd]="col.filterValue" (onChangeAsYmd)="applyDateFilter($event, col, dateendsel.currentAsYmd())" (onCleared)="clearDateFilter(col)"
-                        [disabled]="col.filterInputDisabled" #datesel></eg-date-select>
+                        [disabled]="col.filterInputDisabled || context.dataSource.requestingData" #datesel></eg-date-select>
         <div [hidden]="col.filterOperator !== 'between'" class="form-inline form-group">
           <label for="eg-filter-end-date-select-{{col.name}}" style="width: 3em;" i18n>and</label>
           <eg-date-select [hidden]="col.filterOperator !== 'between'" (onChangeAsYmd)="applyDateFilter(datesel.currentAsYmd(), col, $event)"
+                          [disabled]="col.filterInputDisabled || context.dataSource.requestingData"
                           [required]="col.filterOperator == 'between'" #dateendsel></eg-date-select>
         </div>
       </div>
     <div *ngSwitchCase="'org_unit'">
       <div class="input-group">
         <div ngbDropdown class="d-inline-block" autoClose="outside" placement="bottom-left" [ngClass]="{'eg-grid-col-is-filtered' : col.isFiltered}">
-          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button"><span class="material-icons mat-icon-in-button">filter_list</span></button>
+          <button ngbDropdownToggle class="form-control btn btn-sm btn-outline-dark text-button" [disabled]="context.dataSource.requestingData">
+            <span class="material-icons mat-icon-in-button">filter_list</span>
+          </button>
           <div ngbDropdownMenu class="eg-grid-filter-menu">
             <div class="dropdown-item">
               <label for="eg-filter-op-select-{{col.name}}" i18n>Operator</label>
             </div>
           </div>
         </div>
-        <eg-org-select [applyOrgId]="col.filterValue" (onChange)="applyOrgFilter($event, col)" 
+        <eg-org-select [applyOrgId]="col.filterValue" (onChange)="applyOrgFilter($event, col)"
+          [disabled]="col.filterInputDisabled || context.dataSource.requestingData"
           i18n-placeholder placeholder="Enter library to filter by" #ousel></eg-org-select>
       </div>
     </div>
index 3b22377..eb701ce 100644 (file)
@@ -8,7 +8,7 @@
       <!-- special case for remove filters button -->
       <button *ngIf="gridContext.isFilterable"
         class="btn btn-outline-dark mr-1" (click)="gridContext.removeFilters()"
-        [disabled]="!gridContext.filtersSet()" i18n>
+        [disabled]="!gridContext.filtersSet() || gridContext.dataSource.requestingData" i18n>
         Remove Filters
       </button>
       <button *ngFor="let btn of gridContext.toolbarButtons"
index d40ac55..f4e4396 100644 (file)
@@ -1203,7 +1203,8 @@ export class GridDataSource {
             return this.getRows(pager, this.sort).subscribe(
                 row => {
                     this.data[idx++] = row;
-                    this.requestingData = false;
+                    // not updating this.requestingData, as having
+                    // retrieved one row doesn't mean we're done
                     this.retrievalError = false;
                 },
                 err => {