@sumaris-net/ngx-components 1.6.16 → 1.6.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1636,7 +1636,7 @@ MatAutocompleteField.decorators = [
1636
1636
  { type: Component, args: [{
1637
1637
  // eslint-disable-next-line @angular-eslint/component-selector
1638
1638
  selector: 'mat-autocomplete-field',
1639
- template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <!-- readonly -->\n <mat-form-field *ngIf=\"_readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n [title]=\"displayValue\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\" readonly>\n <ion-text>{{displayWith(value)}}</ion-text>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n </mat-form-field>\n\n <ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"disabled\"\n [title]=\"displayValue\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- Basic select -->\n <mat-select #matSelect\n *ngIf=\"!searchable; else searchableTemplate\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\"\n [tabindex]=\"_tabindex\"\n [panelClass]=\"classList\"\n [style.width]=\"panelWidth\"\n (focus)=\"filterMatSelectFocusEvent($event)\"\n (blur)=\"filterMatSelectBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n [compareWith]=\"equals\"\n [multiple]=\"multiple\"\n [required]=\"required\">\n <mat-select-trigger>{{ displayWith(value) }}</mat-select-trigger>\n\n <!-- header -->\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as isLast\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <!-- None option -->\n <mat-option *ngIf=\"!required\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label><i translate>COMMON.EMPTY_OPTION</i></ion-label>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <ng-container *ngIf=\"$filteredItems | async; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label>{{noResultMessage | translate}}</ion-label>\n </mat-option>\n\n <!-- options -->\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text>{{item | propertyGet: path }}</ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initMatSelectInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n </mat-select>\n\n\n <!--\n NOTE :\n - \"selectInputContent($event) || onFocus.emit($event)\" : call onFocus only when to the input is empty (nothing to select)\n -->\n <ng-template #searchableTemplate>\n <input matInput #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n (keyup.arrowdown)=\"dropButtonClick.emit($event)\">\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [panelWidth]=\"panelWidth\">\n\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as last\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n <ion-text color=\"light\" *ngIf=\"last && itemCount; let count\" class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <ng-container *ngIf=\"$filteredItems | async; else loadingTemplate; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: formControl.value, withAccent: highlightAccent }\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(matInputText.value | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n </ng-template>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"searchable\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix type=\"button\" mat-icon-button tabindex=\"-1\"\n *ngIf=\"enabled && mobile && !searchable && !multiple\"\n [title]=\"'COMMON.BTN_SEARCH'|translate\"\n (click)=\"toggleSearch($event)\">\n <mat-icon>search</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
1639
+ template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <!-- readonly -->\n <mat-form-field *ngIf=\"_readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n [title]=\"displayValue\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\" readonly>\n <ion-text>{{displayWith(value)}}</ion-text>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n </mat-form-field>\n\n <ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"disabled\"\n [title]=\"displayValue\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- Basic select -->\n <mat-select #matSelect\n *ngIf=\"!searchable; else searchableTemplate\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\"\n [tabindex]=\"_tabindex\"\n [panelClass]=\"classList\"\n [style.width]=\"panelWidth\"\n (focus)=\"filterMatSelectFocusEvent($event)\"\n (blur)=\"filterMatSelectBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n [compareWith]=\"equals\"\n [multiple]=\"multiple\"\n [required]=\"required\">\n <mat-select-trigger>{{ displayWith(value) }}</mat-select-trigger>\n\n <!-- header -->\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as isLast\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <!-- None option -->\n <mat-option *ngIf=\"!required\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label><i translate>COMMON.EMPTY_OPTION</i></ion-label>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <ng-container *ngIf=\"$filteredItems | async; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label>{{noResultMessage | translate}}</ion-label>\n </mat-option>\n\n <!-- options -->\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text>{{item | propertyGet: path }}</ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initMatSelectInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n </mat-select>\n\n\n <!--\n NOTE :\n - \"selectInputContent($event) || onFocus.emit($event)\" : call onFocus only when to the input is empty (nothing to select)\n -->\n <ng-template #searchableTemplate>\n <input matInput #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n (keyup.arrowdown)=\"!autocomplete.showPanel && dropButtonClick.emit($event)\">\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [panelWidth]=\"panelWidth\">\n\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i; last as last\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n <ion-text color=\"light\" *ngIf=\"last && itemCount; let count\" class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <ng-container *ngIf=\"$filteredItems | async; else loadingTemplate; let items\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: formControl.value, withAccent: highlightAccent }\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(matInputText.value | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n </ng-template>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"searchable\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix type=\"button\" mat-icon-button tabindex=\"-1\"\n *ngIf=\"enabled && mobile && !searchable && !multiple\"\n [title]=\"'COMMON.BTN_SEARCH'|translate\"\n (click)=\"toggleSearch($event)\">\n <mat-icon>search</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
1640
1640
  providers: [{
1641
1641
  provide: NG_VALUE_ACCESSOR,
1642
1642
  multi: true,
@@ -7516,20 +7516,26 @@ class MatBadgeIconDirective {
7516
7516
  }
7517
7517
  }
7518
7518
  ngOnInit() {
7519
+ // Default value
7519
7520
  this._size = this._size || 'medium';
7520
7521
  this._color = this._color || 'primary';
7521
7522
  if (this._color === 'warn')
7522
7523
  this._color = 'warning';
7523
- this.updateView();
7524
+ this.updateView(true);
7524
7525
  this._subscription = this._$update
7525
- //.pipe(debounceTime(10000))
7526
- .subscribe(() => this.updateView());
7526
+ .pipe(debounceTime(100))
7527
+ .subscribe(() => this.updateView(true));
7527
7528
  }
7528
7529
  ngOnDestroy() {
7529
7530
  var _a;
7530
7531
  (_a = this._subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
7531
7532
  }
7532
- updateView() {
7533
+ updateView(immediate) {
7534
+ // Async by default
7535
+ if (!immediate) {
7536
+ this._$update.next();
7537
+ return;
7538
+ }
7533
7539
  const badge = this.el.nativeElement.querySelector('.mat-badge-content');
7534
7540
  if (!badge)
7535
7541
  return;
@@ -7567,9 +7573,12 @@ class MatBadgeIconDirective {
7567
7573
  badge.style.background = `var(--ion-color-${this._color})`;
7568
7574
  badge.style.color = `var(--ion-color-${this._color}-contrast)`;
7569
7575
  }
7570
- badge.style.alignItems = 'center';
7571
- badge.style.justifyContent = 'center';
7572
- badge.style.display = 'flex';
7576
+ if (badge.style.display !== 'inline-block')
7577
+ badge.style.display = 'inline-block';
7578
+ if (badge.style.alignItems !== 'center')
7579
+ badge.style.alignItems = 'center';
7580
+ if (badge.style.justifyContent !== 'center')
7581
+ badge.style.justifyContent = 'center';
7573
7582
  }
7574
7583
  }
7575
7584
  MatBadgeIconDirective.decorators = [
@@ -21597,7 +21606,7 @@ class AppTable {
21597
21606
  merge(
21598
21607
  // Listen sort events
21599
21608
  this.sort && this.sort.sortChange
21600
- .pipe(mergeMap(() => __awaiter(this, void 0, void 0, function* () { return this.saveBeforeAction('sort'); })), filter(res => res === true),
21609
+ .pipe(filter(() => !this.sort.disabled), mergeMap(() => __awaiter(this, void 0, void 0, function* () { return this.saveBeforeAction('sort'); })), filter(res => res === true),
21601
21610
  // Save sort in settings
21602
21611
  tap(() => {
21603
21612
  const value = [this.sort.active, this.sort.direction || 'asc'].join(':');
@@ -21614,7 +21623,9 @@ class AppTable {
21614
21623
  });
21615
21624
  // If the user changes the sort order, reset back to the first page.
21616
21625
  if (this.sort && this.paginator) {
21617
- this.registerSubscription(this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0));
21626
+ this.registerSubscription(this.sort.sortChange
21627
+ .pipe(filter(() => !this.sort.disabled))
21628
+ .subscribe(() => this.paginator.pageIndex = 0));
21618
21629
  }
21619
21630
  }
21620
21631
  ngOnDestroy() {
@@ -21839,7 +21850,7 @@ class AppTable {
21839
21850
  return true;
21840
21851
  }
21841
21852
  save(opts) {
21842
- var _a, _b;
21853
+ var _a, _b, _c, _d;
21843
21854
  return __awaiter(this, void 0, void 0, function* () {
21844
21855
  opts = Object.assign({ keepEditing: this.keepEditedRowOnSave }, opts);
21845
21856
  if (this.readOnly) {
@@ -21847,8 +21858,8 @@ class AppTable {
21847
21858
  }
21848
21859
  this.resetError();
21849
21860
  // Keep edited row id (should be done BEFORE confirmEditCreate() )
21850
- this.previouslyEditedRowId = opts.keepEditing && ((_a = this.editedRow) === null || _a === void 0 ? void 0 : _a.editing) ? this.editedRow.id : undefined;
21851
- const previouslyEditedData = isNotNil(this.previouslyEditedRowId) && this.editedRow.currentData || ((_b = this.singleSelectedRow) === null || _b === void 0 ? void 0 : _b.currentData);
21861
+ this.previouslyEditedRowId = opts.keepEditing && ((((_a = this.editedRow) === null || _a === void 0 ? void 0 : _a.editing) ? this.editedRow.id : undefined) || ((_b = this.singleSelectedRow) === null || _b === void 0 ? void 0 : _b.id));
21862
+ const previouslyEditedData = isNotNil(this.previouslyEditedRowId) && ((_c = this.editedRow) === null || _c === void 0 ? void 0 : _c.currentData) || ((_d = this.singleSelectedRow) === null || _d === void 0 ? void 0 : _d.currentData);
21852
21863
  if (!this.confirmEditCreate()) {
21853
21864
  throw { code: ErrorCodes$2.TABLE_INVALID_ROW_ERROR, message: 'ERROR.TABLE_INVALID_ROW_ERROR' };
21854
21865
  }
@@ -21986,6 +21997,7 @@ class AppTable {
21986
21997
  const canDelete = yield this.canDeleteRows(rows, opts);
21987
21998
  if (!canDelete)
21988
21999
  return 0; // Cannot delete
22000
+ // If data need to be saved first
21989
22001
  if (this.saveBeforeDelete) {
21990
22002
  // Cancel invalid rows (because of save() will fail, if invalid rows exists)
21991
22003
  rows = rows.reduce((res, row) => {
@@ -22001,25 +22013,31 @@ class AppTable {
22001
22013
  }
22002
22014
  return res.concat(row);
22003
22015
  }, []);
22004
- if (isEmptyArray(rows))
22005
- return 0;
22006
- // If data need to be saved first: do it
22007
- const saved = yield this.saveBeforeAction('delete');
22008
- if (!saved) {
22009
- // Stop if save cancelled or save failed
22010
- return;
22016
+ // Apply save, only if there is still some rows to delete
22017
+ // WARN: If no more rows (e.g. because all has been cancelled) then continue anyway to clear editedRow and selection (issue IMAGINE-669)
22018
+ if (isNotEmptyArray(rows)) {
22019
+ // Save data (e.g. when using memory service)
22020
+ const saved = yield this.saveBeforeAction('delete');
22021
+ if (!saved) {
22022
+ // Stop if save cancelled or save failed
22023
+ return;
22024
+ }
22011
22025
  }
22012
22026
  }
22013
- if (this.debug)
22014
- console.debug('[table] Delete selection...');
22015
- const rowsToDelete = rows.slice()
22016
- // Reverse row order
22017
- // This is a workaround, need because row.delete() has async execution
22018
- // and index cache is updated with a delay)
22019
- .sort((a, b) => a.id > b.id ? -1 : 1);
22020
22027
  try {
22021
- const deleteCount = rowsToDelete.length;
22022
- yield this._dataSource.deleteAll(rowsToDelete);
22028
+ const deleteCount = rows.length;
22029
+ // Apply deletion on datasource
22030
+ // If no more rows to delete, continue anyway to clear editedRow and selection (issue IMAGINE-669)
22031
+ if (deleteCount) {
22032
+ if (this.debug)
22033
+ console.debug('[table] Delete selected rows...');
22034
+ // Reverse row order (on a copy)
22035
+ // This is a workaround, need because row.delete() has async execution
22036
+ // and index cache is updated with a delay
22037
+ rows = rows.slice()
22038
+ .sort((a, b) => a.id > b.id ? -1 : 1);
22039
+ yield this._dataSource.deleteAll(rows);
22040
+ }
22023
22041
  // DO not update manually, because watchALl().subscribe() will update this count
22024
22042
  //this.totalRowCount -= deleteCount;
22025
22043
  //this.visibleRowCount -= deleteCount;
@@ -22027,7 +22045,8 @@ class AppTable {
22027
22045
  this.editedRow = undefined;
22028
22046
  this.markAsDirty({ emitEvent: false /*markForCheck() is called just after*/ });
22029
22047
  this.markForCheck();
22030
- this.onAfterDeletedRows.next(rowsToDelete);
22048
+ if (deleteCount)
22049
+ this.onAfterDeletedRows.next(rows);
22031
22050
  return deleteCount;
22032
22051
  }
22033
22052
  catch (err) {