@gp-grid/angular 0.12.0 → 0.12.1
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.
|
@@ -32,37 +32,37 @@ const TEMPLATE$1 = `
|
|
|
32
32
|
</ng-container>
|
|
33
33
|
} @else {
|
|
34
34
|
<span class="gp-grid-header-text">{{ entry.column.headerName ?? entry.column.field }}</span>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
</span>
|
|
50
|
-
@if ((headerData?.sortIndex ?? 0) > 0) {
|
|
51
|
-
<span class="gp-grid-sort-index">{{ headerData?.sortIndex }}</span>
|
|
52
|
-
}
|
|
53
|
-
</span>
|
|
54
|
-
}
|
|
55
|
-
@if (entry.column.filterable) {
|
|
56
|
-
<span
|
|
57
|
-
[class]="'gp-grid-filter-icon' + (headerData?.hasFilter ? ' active' : '')"
|
|
58
|
-
(pointerdown)="onFilterPointerDown($event, entry.originalIndex)">
|
|
59
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
|
60
|
-
<path d="M4 4h16l-6 8v5l-4 2v-7L4 4z"/>
|
|
35
|
+
}
|
|
36
|
+
<span class="gp-grid-header-icons">
|
|
37
|
+
@if (sortingEnabled() && entry.column.sortable !== false) {
|
|
38
|
+
<span class="gp-grid-sort-arrows">
|
|
39
|
+
<span class="gp-grid-sort-arrows-stack">
|
|
40
|
+
<svg
|
|
41
|
+
[class]="'gp-grid-sort-arrow-up' + (headerData?.sortDirection === 'asc' ? ' active' : '')"
|
|
42
|
+
width="8" height="6" viewBox="0 0 8 6">
|
|
43
|
+
<path d="M4 0L8 6H0L4 0Z" fill="currentColor"/>
|
|
44
|
+
</svg>
|
|
45
|
+
<svg
|
|
46
|
+
[class]="'gp-grid-sort-arrow-down' + (headerData?.sortDirection === 'desc' ? ' active' : '')"
|
|
47
|
+
width="8" height="6" viewBox="0 0 8 6">
|
|
48
|
+
<path d="M4 6L0 0H8L4 6Z" fill="currentColor"/>
|
|
61
49
|
</svg>
|
|
62
50
|
</span>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
@if ((headerData?.sortIndex ?? 0) > 0) {
|
|
52
|
+
<span class="gp-grid-sort-index">{{ headerData?.sortIndex }}</span>
|
|
53
|
+
}
|
|
54
|
+
</span>
|
|
55
|
+
}
|
|
56
|
+
@if (entry.column.filterable !== false) {
|
|
57
|
+
<span
|
|
58
|
+
[class]="'gp-grid-filter-icon' + (headerData?.hasFilter ? ' active' : '')"
|
|
59
|
+
(pointerdown)="onFilterPointerDown($event, entry.originalIndex)">
|
|
60
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
|
61
|
+
<path d="M4 4h16l-6 8v5l-4 2v-7L4 4z"/>
|
|
62
|
+
</svg>
|
|
63
|
+
</span>
|
|
64
|
+
}
|
|
65
|
+
</span>
|
|
66
66
|
@if (entry.column.resizable !== false) {
|
|
67
67
|
<div
|
|
68
68
|
class="gp-grid-header-resize-handle"
|
|
@@ -122,7 +122,7 @@ class GridHeaderComponent {
|
|
|
122
122
|
}
|
|
123
123
|
headerParams(column, colIndex, headerData) {
|
|
124
124
|
const sortable = this.sortingEnabled() && column.sortable !== false;
|
|
125
|
-
const filterable = column.filterable
|
|
125
|
+
const filterable = column.filterable !== false;
|
|
126
126
|
return {
|
|
127
127
|
column,
|
|
128
128
|
colIndex,
|
|
@@ -144,7 +144,7 @@ class GridHeaderComponent {
|
|
|
144
144
|
};
|
|
145
145
|
}
|
|
146
146
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: GridHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
147
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: GridHeaderComponent, isStandalone: true, selector: "gp-grid-header", inputs: { headerHeight: { classPropertyName: "headerHeight", publicName: "headerHeight", isSignal: true, isRequired: true, transformFunction: null }, scrollLeft: { classPropertyName: "scrollLeft", publicName: "scrollLeft", isSignal: true, isRequired: true, transformFunction: null }, contentWidth: { classPropertyName: "contentWidth", publicName: "contentWidth", isSignal: true, isRequired: true, transformFunction: null }, totalWidth: { classPropertyName: "totalWidth", publicName: "totalWidth", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, visibleColumnsWithIndices: { classPropertyName: "visibleColumnsWithIndices", publicName: "visibleColumnsWithIndices", isSignal: true, isRequired: true, transformFunction: null }, columnPositions: { classPropertyName: "columnPositions", publicName: "columnPositions", isSignal: true, isRequired: true, transformFunction: null }, columnWidths: { classPropertyName: "columnWidths", publicName: "columnWidths", isSignal: true, isRequired: true, transformFunction: null }, headers: { classPropertyName: "headers", publicName: "headers", isSignal: true, isRequired: true, transformFunction: null }, sortingEnabled: { classPropertyName: "sortingEnabled", publicName: "sortingEnabled", isSignal: true, isRequired: false, transformFunction: null }, headerRenderers: { classPropertyName: "headerRenderers", publicName: "headerRenderers", isSignal: true, isRequired: false, transformFunction: null }, globalHeaderRenderer: { classPropertyName: "globalHeaderRenderer", publicName: "globalHeaderRenderer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { headerPointerDown: "headerPointerDown", filterPointerDown: "filterPointerDown", resizePointerDown: "resizePointerDown", headerSort: "headerSort", headerFilterOpen: "headerFilterOpen" }, ngImport: i0, template: "\n <div\n class=\"gp-grid-header\"\n [class.gp-grid-header--loading]=\"isLoading()\"\n [style.height.px]=\"headerHeight()\">\n <div\n style=\"position: absolute; top: 0; left: 0;\"\n [style.transform]=\"transformStyle()\"\n [style.width.px]=\"innerWidth()\"\n [style.height.px]=\"headerHeight()\">\n @for (entry of visibleColumnsWithIndices(); track entry.originalIndex; let i = $index) {\n @let colW = columnWidths()[i] ?? 0;\n @let headerData = headers().get(entry.originalIndex);\n @let tpl = headerTemplate(entry.column);\n <div\n class=\"gp-grid-header-cell\"\n [attr.data-col-index]=\"entry.originalIndex\"\n [style.left.px]=\"columnPositions()[i]\"\n [style.width.px]=\"colW\"\n [style.height.px]=\"headerHeight()\"\n (pointerdown)=\"onHeaderPointerDown($event, entry.originalIndex, colW)\">\n @if (tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: headerParams(entry.column, entry.originalIndex, headerData) }\">\n </ng-container>\n } @else {\n <span class=\"gp-grid-header-text\">{{ entry.column.headerName ?? entry.column.field }}</span>\n
|
|
147
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: GridHeaderComponent, isStandalone: true, selector: "gp-grid-header", inputs: { headerHeight: { classPropertyName: "headerHeight", publicName: "headerHeight", isSignal: true, isRequired: true, transformFunction: null }, scrollLeft: { classPropertyName: "scrollLeft", publicName: "scrollLeft", isSignal: true, isRequired: true, transformFunction: null }, contentWidth: { classPropertyName: "contentWidth", publicName: "contentWidth", isSignal: true, isRequired: true, transformFunction: null }, totalWidth: { classPropertyName: "totalWidth", publicName: "totalWidth", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, visibleColumnsWithIndices: { classPropertyName: "visibleColumnsWithIndices", publicName: "visibleColumnsWithIndices", isSignal: true, isRequired: true, transformFunction: null }, columnPositions: { classPropertyName: "columnPositions", publicName: "columnPositions", isSignal: true, isRequired: true, transformFunction: null }, columnWidths: { classPropertyName: "columnWidths", publicName: "columnWidths", isSignal: true, isRequired: true, transformFunction: null }, headers: { classPropertyName: "headers", publicName: "headers", isSignal: true, isRequired: true, transformFunction: null }, sortingEnabled: { classPropertyName: "sortingEnabled", publicName: "sortingEnabled", isSignal: true, isRequired: false, transformFunction: null }, headerRenderers: { classPropertyName: "headerRenderers", publicName: "headerRenderers", isSignal: true, isRequired: false, transformFunction: null }, globalHeaderRenderer: { classPropertyName: "globalHeaderRenderer", publicName: "globalHeaderRenderer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { headerPointerDown: "headerPointerDown", filterPointerDown: "filterPointerDown", resizePointerDown: "resizePointerDown", headerSort: "headerSort", headerFilterOpen: "headerFilterOpen" }, ngImport: i0, template: "\n <div\n class=\"gp-grid-header\"\n [class.gp-grid-header--loading]=\"isLoading()\"\n [style.height.px]=\"headerHeight()\">\n <div\n style=\"position: absolute; top: 0; left: 0;\"\n [style.transform]=\"transformStyle()\"\n [style.width.px]=\"innerWidth()\"\n [style.height.px]=\"headerHeight()\">\n @for (entry of visibleColumnsWithIndices(); track entry.originalIndex; let i = $index) {\n @let colW = columnWidths()[i] ?? 0;\n @let headerData = headers().get(entry.originalIndex);\n @let tpl = headerTemplate(entry.column);\n <div\n class=\"gp-grid-header-cell\"\n [attr.data-col-index]=\"entry.originalIndex\"\n [style.left.px]=\"columnPositions()[i]\"\n [style.width.px]=\"colW\"\n [style.height.px]=\"headerHeight()\"\n (pointerdown)=\"onHeaderPointerDown($event, entry.originalIndex, colW)\">\n @if (tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: headerParams(entry.column, entry.originalIndex, headerData) }\">\n </ng-container>\n } @else {\n <span class=\"gp-grid-header-text\">{{ entry.column.headerName ?? entry.column.field }}</span>\n }\n <span class=\"gp-grid-header-icons\">\n @if (sortingEnabled() && entry.column.sortable !== false) {\n <span class=\"gp-grid-sort-arrows\">\n <span class=\"gp-grid-sort-arrows-stack\">\n <svg\n [class]=\"'gp-grid-sort-arrow-up' + (headerData?.sortDirection === 'asc' ? ' active' : '')\"\n width=\"8\" height=\"6\" viewBox=\"0 0 8 6\">\n <path d=\"M4 0L8 6H0L4 0Z\" fill=\"currentColor\"/>\n </svg>\n <svg\n [class]=\"'gp-grid-sort-arrow-down' + (headerData?.sortDirection === 'desc' ? ' active' : '')\"\n width=\"8\" height=\"6\" viewBox=\"0 0 8 6\">\n <path d=\"M4 6L0 0H8L4 6Z\" fill=\"currentColor\"/>\n </svg>\n </span>\n @if ((headerData?.sortIndex ?? 0) > 0) {\n <span class=\"gp-grid-sort-index\">{{ headerData?.sortIndex }}</span>\n }\n </span>\n }\n @if (entry.column.filterable !== false) {\n <span\n [class]=\"'gp-grid-filter-icon' + (headerData?.hasFilter ? ' active' : '')\"\n (pointerdown)=\"onFilterPointerDown($event, entry.originalIndex)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M4 4h16l-6 8v5l-4 2v-7L4 4z\"/>\n </svg>\n </span>\n }\n </span>\n @if (entry.column.resizable !== false) {\n <div\n class=\"gp-grid-header-resize-handle\"\n (pointerdown)=\"onResizePointerDown($event, entry.originalIndex, colW)\">\n </div>\n }\n </div>\n }\n </div>\n </div>\n", isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
148
148
|
}
|
|
149
149
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: GridHeaderComponent, decorators: [{
|
|
150
150
|
type: Component,
|
|
@@ -539,13 +539,13 @@ const FILTER_POPUP_TEMPLATE = `
|
|
|
539
539
|
(change)="includeBlanks = $any($event.target).checked" />
|
|
540
540
|
<span class="gp-grid-filter-blank">(Blanks)</span>
|
|
541
541
|
</label>
|
|
542
|
-
@for (
|
|
542
|
+
@for (entry of filteredUniqueEntries(); track entry.key) {
|
|
543
543
|
<label class="gp-grid-filter-option">
|
|
544
544
|
<input
|
|
545
545
|
type="checkbox"
|
|
546
|
-
[checked]="selectedValues.has(
|
|
547
|
-
(change)="toggleValue(
|
|
548
|
-
<span>{{
|
|
546
|
+
[checked]="selectedValues.has(entry.key)"
|
|
547
|
+
(change)="toggleValue(entry.key, $any($event.target).checked)" />
|
|
548
|
+
<span>{{ entry.label }}</span>
|
|
549
549
|
</label>
|
|
550
550
|
}
|
|
551
551
|
</div>
|
|
@@ -650,19 +650,19 @@ const defaultNumberCondition = () => ({
|
|
|
650
650
|
valueTo: '',
|
|
651
651
|
nextOperator: 'and',
|
|
652
652
|
});
|
|
653
|
-
const computeUniqueValues = (distinctValues) => {
|
|
653
|
+
const computeUniqueValues = (distinctValues, formatter) => {
|
|
654
654
|
const seen = new Set();
|
|
655
655
|
const result = [];
|
|
656
656
|
for (const val of distinctValues) {
|
|
657
657
|
if (val === null || val === undefined || val === '')
|
|
658
658
|
continue;
|
|
659
|
-
const
|
|
660
|
-
if (!seen.has(
|
|
661
|
-
seen.add(
|
|
662
|
-
result.push(
|
|
659
|
+
const key = String(val);
|
|
660
|
+
if (!seen.has(key)) {
|
|
661
|
+
seen.add(key);
|
|
662
|
+
result.push({ key, label: formatter ? formatter(val) : key });
|
|
663
663
|
}
|
|
664
664
|
}
|
|
665
|
-
return result.sort();
|
|
665
|
+
return result.sort((a, b) => a.label.localeCompare(b.label, undefined, { numeric: true, sensitivity: 'base' }));
|
|
666
666
|
};
|
|
667
667
|
const initTextState = (filter, uniqueValues) => {
|
|
668
668
|
if (!filter)
|
|
@@ -833,16 +833,19 @@ class FilterPopupComponent {
|
|
|
833
833
|
return isNumberColumn(this.column());
|
|
834
834
|
}
|
|
835
835
|
showValuesMode() {
|
|
836
|
-
return this.
|
|
836
|
+
return this.uniqueEntries().length <= MAX_CHECKBOX_VALUES;
|
|
837
|
+
}
|
|
838
|
+
uniqueEntries() {
|
|
839
|
+
return computeUniqueValues(this.distinctValues(), this.column().valueFormatter);
|
|
837
840
|
}
|
|
838
841
|
uniqueValues() {
|
|
839
|
-
return
|
|
842
|
+
return this.uniqueEntries().map(e => e.key);
|
|
840
843
|
}
|
|
841
|
-
|
|
844
|
+
filteredUniqueEntries() {
|
|
842
845
|
const search = this.searchText.toLowerCase();
|
|
843
846
|
if (!search)
|
|
844
|
-
return this.
|
|
845
|
-
return this.
|
|
847
|
+
return this.uniqueEntries();
|
|
848
|
+
return this.uniqueEntries().filter(e => e.label.toLowerCase().includes(search));
|
|
846
849
|
}
|
|
847
850
|
toggleValue(val, checked) {
|
|
848
851
|
if (checked) {
|
|
@@ -938,7 +941,7 @@ class FilterPopupComponent {
|
|
|
938
941
|
this.updatePosition();
|
|
939
942
|
};
|
|
940
943
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: FilterPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
941
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: FilterPopupComponent, isStandalone: true, selector: "gp-grid-filter-popup", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, colIndex: { classPropertyName: "colIndex", publicName: "colIndex", isSignal: true, isRequired: true, transformFunction: null }, anchorEl: { classPropertyName: "anchorEl", publicName: "anchorEl", isSignal: true, isRequired: true, transformFunction: null }, distinctValues: { classPropertyName: "distinctValues", publicName: "distinctValues", isSignal: true, isRequired: true, transformFunction: null }, currentFilter: { classPropertyName: "currentFilter", publicName: "currentFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { apply: "apply", close: "close" }, host: { listeners: { "keydown.escape": "onEscape()" } }, viewQueries: [{ propertyName: "popupEl", first: true, predicate: ["popupEl"], descendants: true }], ngImport: i0, template: "\n<div\n #popupEl\n class=\"gp-grid-filter-popup\"\n [style.position]=\"'fixed'\"\n [style.zIndex]=\"10000\"\n [style.top.px]=\"popupTop()\"\n [style.left.px]=\"popupLeft()\"\n [style.minWidth.px]=\"popupMinWidth()\"\n [style.visibility]=\"positioned() ? 'visible' : 'hidden'\"\n (keydown.escape)=\"close.emit()\"\n (click)=\"$event.stopPropagation()\">\n\n <div class=\"gp-grid-filter-header\">\n Filter: {{ column().headerName ?? column().field }}\n </div>\n\n <div [class]=\"'gp-grid-filter-content ' + (isNumberColumn() ? 'gp-grid-filter-number' : 'gp-grid-filter-text')\">\n @if (isNumberColumn()) {\n @for (cond of numberConditions; track $index; let i = $index) {\n <div class=\"gp-grid-filter-condition\">\n @if (i > 0) {\n <div class=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n [class.active]=\"numberConditions[i - 1]?.nextOperator === 'and'\"\n (click)=\"setNumberNextOp(i - 1, 'and')\">\n AND\n </button>\n <button\n type=\"button\"\n [class.active]=\"numberConditions[i - 1]?.nextOperator === 'or'\"\n (click)=\"setNumberNextOp(i - 1, 'or')\">\n OR\n </button>\n </div>\n }\n <div class=\"gp-grid-filter-row\">\n <select\n [value]=\"cond.operator\"\n (change)=\"onNumberOperatorChange(i, $any($event.target).value)\">\n @for (op of numberOperators; track op.value) {\n <option [value]=\"op.value\">{{ op.label }}</option>\n }\n </select>\n @if (!isValueLessNumberOp(cond.operator)) {\n <input\n type=\"number\"\n [value]=\"cond.value\"\n (input)=\"cond.value = $any($event.target).value\"\n placeholder=\"Value\" />\n @if (cond.operator === 'between') {\n <span class=\"gp-grid-filter-to\">to</span>\n <input\n type=\"number\"\n [value]=\"cond.valueTo\"\n (input)=\"cond.valueTo = $any($event.target).value\"\n placeholder=\"Value\" />\n }\n }\n @if (numberConditions.length > 1) {\n <button\n type=\"button\"\n class=\"gp-grid-filter-remove\"\n (click)=\"removeNumberCondition(i)\">\u00D7</button>\n }\n </div>\n </div>\n }\n <button type=\"button\" class=\"gp-grid-filter-add\" (click)=\"addNumberCondition()\">\n + Add condition\n </button>\n } @else {\n @if (showValuesMode()) {\n <div class=\"gp-grid-filter-mode-toggle\">\n <button\n type=\"button\"\n [class.active]=\"filterMode === 'values'\"\n (click)=\"filterMode = 'values'\">\n Values\n </button>\n <button\n type=\"button\"\n [class.active]=\"filterMode === 'condition'\"\n (click)=\"filterMode = 'condition'\">\n Condition\n </button>\n </div>\n }\n\n @if (filterMode === 'values' && showValuesMode()) {\n <input\n class=\"gp-grid-filter-search\"\n type=\"text\"\n [value]=\"searchText\"\n (input)=\"searchText = $any($event.target).value\"\n placeholder=\"Search...\" />\n <div class=\"gp-grid-filter-actions\">\n <button type=\"button\" (click)=\"selectAll()\">Select All</button>\n <button type=\"button\" (click)=\"deselectAll()\">Deselect All</button>\n </div>\n <div class=\"gp-grid-filter-list\">\n <label class=\"gp-grid-filter-option\">\n <input\n type=\"checkbox\"\n [checked]=\"includeBlanks\"\n (change)=\"includeBlanks = $any($event.target).checked\" />\n <span class=\"gp-grid-filter-blank\">(Blanks)</span>\n </label>\n @for (
|
|
944
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: FilterPopupComponent, isStandalone: true, selector: "gp-grid-filter-popup", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, colIndex: { classPropertyName: "colIndex", publicName: "colIndex", isSignal: true, isRequired: true, transformFunction: null }, anchorEl: { classPropertyName: "anchorEl", publicName: "anchorEl", isSignal: true, isRequired: true, transformFunction: null }, distinctValues: { classPropertyName: "distinctValues", publicName: "distinctValues", isSignal: true, isRequired: true, transformFunction: null }, currentFilter: { classPropertyName: "currentFilter", publicName: "currentFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { apply: "apply", close: "close" }, host: { listeners: { "keydown.escape": "onEscape()" } }, viewQueries: [{ propertyName: "popupEl", first: true, predicate: ["popupEl"], descendants: true }], ngImport: i0, template: "\n<div\n #popupEl\n class=\"gp-grid-filter-popup\"\n [style.position]=\"'fixed'\"\n [style.zIndex]=\"10000\"\n [style.top.px]=\"popupTop()\"\n [style.left.px]=\"popupLeft()\"\n [style.minWidth.px]=\"popupMinWidth()\"\n [style.visibility]=\"positioned() ? 'visible' : 'hidden'\"\n (keydown.escape)=\"close.emit()\"\n (click)=\"$event.stopPropagation()\">\n\n <div class=\"gp-grid-filter-header\">\n Filter: {{ column().headerName ?? column().field }}\n </div>\n\n <div [class]=\"'gp-grid-filter-content ' + (isNumberColumn() ? 'gp-grid-filter-number' : 'gp-grid-filter-text')\">\n @if (isNumberColumn()) {\n @for (cond of numberConditions; track $index; let i = $index) {\n <div class=\"gp-grid-filter-condition\">\n @if (i > 0) {\n <div class=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n [class.active]=\"numberConditions[i - 1]?.nextOperator === 'and'\"\n (click)=\"setNumberNextOp(i - 1, 'and')\">\n AND\n </button>\n <button\n type=\"button\"\n [class.active]=\"numberConditions[i - 1]?.nextOperator === 'or'\"\n (click)=\"setNumberNextOp(i - 1, 'or')\">\n OR\n </button>\n </div>\n }\n <div class=\"gp-grid-filter-row\">\n <select\n [value]=\"cond.operator\"\n (change)=\"onNumberOperatorChange(i, $any($event.target).value)\">\n @for (op of numberOperators; track op.value) {\n <option [value]=\"op.value\">{{ op.label }}</option>\n }\n </select>\n @if (!isValueLessNumberOp(cond.operator)) {\n <input\n type=\"number\"\n [value]=\"cond.value\"\n (input)=\"cond.value = $any($event.target).value\"\n placeholder=\"Value\" />\n @if (cond.operator === 'between') {\n <span class=\"gp-grid-filter-to\">to</span>\n <input\n type=\"number\"\n [value]=\"cond.valueTo\"\n (input)=\"cond.valueTo = $any($event.target).value\"\n placeholder=\"Value\" />\n }\n }\n @if (numberConditions.length > 1) {\n <button\n type=\"button\"\n class=\"gp-grid-filter-remove\"\n (click)=\"removeNumberCondition(i)\">\u00D7</button>\n }\n </div>\n </div>\n }\n <button type=\"button\" class=\"gp-grid-filter-add\" (click)=\"addNumberCondition()\">\n + Add condition\n </button>\n } @else {\n @if (showValuesMode()) {\n <div class=\"gp-grid-filter-mode-toggle\">\n <button\n type=\"button\"\n [class.active]=\"filterMode === 'values'\"\n (click)=\"filterMode = 'values'\">\n Values\n </button>\n <button\n type=\"button\"\n [class.active]=\"filterMode === 'condition'\"\n (click)=\"filterMode = 'condition'\">\n Condition\n </button>\n </div>\n }\n\n @if (filterMode === 'values' && showValuesMode()) {\n <input\n class=\"gp-grid-filter-search\"\n type=\"text\"\n [value]=\"searchText\"\n (input)=\"searchText = $any($event.target).value\"\n placeholder=\"Search...\" />\n <div class=\"gp-grid-filter-actions\">\n <button type=\"button\" (click)=\"selectAll()\">Select All</button>\n <button type=\"button\" (click)=\"deselectAll()\">Deselect All</button>\n </div>\n <div class=\"gp-grid-filter-list\">\n <label class=\"gp-grid-filter-option\">\n <input\n type=\"checkbox\"\n [checked]=\"includeBlanks\"\n (change)=\"includeBlanks = $any($event.target).checked\" />\n <span class=\"gp-grid-filter-blank\">(Blanks)</span>\n </label>\n @for (entry of filteredUniqueEntries(); track entry.key) {\n <label class=\"gp-grid-filter-option\">\n <input\n type=\"checkbox\"\n [checked]=\"selectedValues.has(entry.key)\"\n (change)=\"toggleValue(entry.key, $any($event.target).checked)\" />\n <span>{{ entry.label }}</span>\n </label>\n }\n </div>\n }\n\n @if (filterMode === 'condition') {\n @for (cond of textConditions; track $index; let i = $index) {\n <div class=\"gp-grid-filter-condition\">\n @if (i > 0) {\n <div class=\"gp-grid-filter-combination\">\n <button\n type=\"button\"\n [class.active]=\"textConditions[i - 1]?.nextOperator === 'and'\"\n (click)=\"setTextNextOp(i - 1, 'and')\">\n AND\n </button>\n <button\n type=\"button\"\n [class.active]=\"textConditions[i - 1]?.nextOperator === 'or'\"\n (click)=\"setTextNextOp(i - 1, 'or')\">\n OR\n </button>\n </div>\n }\n <div class=\"gp-grid-filter-row\">\n <select\n [value]=\"cond.operator\"\n (change)=\"onTextOperatorChange(i, $any($event.target).value)\">\n @for (op of textOperators; track op.value) {\n <option [value]=\"op.value\">{{ op.label }}</option>\n }\n </select>\n @if (!isValueLessTextOp(cond.operator)) {\n <input\n class=\"gp-grid-filter-text-input\"\n type=\"text\"\n [value]=\"cond.value\"\n (input)=\"cond.value = $any($event.target).value\"\n placeholder=\"Value\" />\n }\n @if (textConditions.length > 1) {\n <button\n type=\"button\"\n class=\"gp-grid-filter-remove\"\n (click)=\"removeTextCondition(i)\">\u00D7</button>\n }\n </div>\n </div>\n }\n <button type=\"button\" class=\"gp-grid-filter-add\" (click)=\"addTextCondition()\">\n + Add condition\n </button>\n }\n }\n\n <div class=\"gp-grid-filter-buttons\">\n <button type=\"button\" class=\"gp-grid-filter-btn-clear\" (click)=\"handleClear()\">\n Clear\n </button>\n <button type=\"button\" class=\"gp-grid-filter-btn-apply\" (click)=\"handleApply()\">\n Apply\n </button>\n </div>\n </div>\n</div>\n", isInline: true, changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
942
945
|
}
|
|
943
946
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: FilterPopupComponent, decorators: [{
|
|
944
947
|
type: Component,
|
|
@@ -1428,10 +1431,10 @@ class GpGridComponent {
|
|
|
1428
1431
|
getHeaderHeight: () => this.headerHeight(),
|
|
1429
1432
|
});
|
|
1430
1433
|
constructor() {
|
|
1431
|
-
effect(() => this.bindings.applyPendingScroll());
|
|
1434
|
+
effect(() => this.bindings.applyPendingScroll(), { allowSignalWrites: true });
|
|
1432
1435
|
effect(() => this.bindings.syncHighlighting(this.highlighting()));
|
|
1433
|
-
effect(() => this.bindings.syncColumns(this.columns()));
|
|
1434
|
-
effect(() => this.bindings.syncRows(this.rows(), this.dataSource()));
|
|
1436
|
+
effect(() => this.bindings.syncColumns(this.columns()), { allowSignalWrites: true });
|
|
1437
|
+
effect(() => this.bindings.syncRows(this.rows(), this.dataSource()), { allowSignalWrites: true });
|
|
1435
1438
|
}
|
|
1436
1439
|
ngOnInit() {
|
|
1437
1440
|
const core = buildGridCore({
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gp-grid/angular",
|
|
3
3
|
"description": "A high-performance Angular data grid component with virtual scrolling, cell selection, sorting, filtering, and Excel-like editing",
|
|
4
|
-
"version": "0.12.
|
|
4
|
+
"version": "0.12.1",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"module": "fesm2022/gp-grid-angular.mjs",
|
|
7
7
|
"typings": "types/gp-grid-angular.d.ts",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@angular/core": ">=18.0.0"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@gp-grid/core": "0.12.
|
|
54
|
+
"@gp-grid/core": "0.12.1",
|
|
55
55
|
"tslib": "^2.8.1"
|
|
56
56
|
},
|
|
57
57
|
"sideEffects": false,
|
|
@@ -156,6 +156,10 @@ interface NumberConditionState {
|
|
|
156
156
|
nextOperator: 'and' | 'or';
|
|
157
157
|
}
|
|
158
158
|
type FilterMode = 'values' | 'condition';
|
|
159
|
+
interface FilterEntry {
|
|
160
|
+
key: string;
|
|
161
|
+
label: string;
|
|
162
|
+
}
|
|
159
163
|
|
|
160
164
|
declare class FilterPopupComponent implements AfterViewInit, OnDestroy {
|
|
161
165
|
popupEl: ElementRef<HTMLDivElement>;
|
|
@@ -195,8 +199,9 @@ declare class FilterPopupComponent implements AfterViewInit, OnDestroy {
|
|
|
195
199
|
onEscape(): void;
|
|
196
200
|
isNumberColumn(): boolean;
|
|
197
201
|
showValuesMode(): boolean;
|
|
202
|
+
uniqueEntries(): FilterEntry[];
|
|
198
203
|
uniqueValues(): string[];
|
|
199
|
-
|
|
204
|
+
filteredUniqueEntries(): FilterEntry[];
|
|
200
205
|
toggleValue(val: string, checked: boolean): void;
|
|
201
206
|
selectAll(): void;
|
|
202
207
|
deselectAll(): void;
|