ngx-column-filter-popup 1.0.0

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.
package/README.md ADDED
@@ -0,0 +1,451 @@
1
+ # Column Filter Library
2
+
3
+ A powerful, reusable Angular column filter component with support for multiple field types, advanced filtering rules, and customizable match modes.
4
+
5
+ [![npm version](https://badge.fury.io/js/%40blumptech%2Fcolumn-filter.svg)](https://badge.fury.io/js/%40blumptech%2Fcolumn-filter)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - ✅ **Multiple Filter Rules**: Add multiple filter conditions per column
11
+ - ✅ **Multiple Field Types**: Specialized filters for different data types
12
+ - **Text** - Text fields (default)
13
+ - **Currency** - Currency values with symbol support
14
+ - **Age/Number** - Numeric values
15
+ - **Date** - Date values with date picker
16
+ - **Status** - Predefined status options dropdown
17
+ - ✅ **Global Match Mode**: Choose how to combine multiple rules
18
+ - **Match All Rules** (AND Logic): All rules must match
19
+ - **Match Any Rule** (OR Logic): Any rule can match (default)
20
+ - ✅ **Various Match Types**: Different matching options based on field type
21
+ - ✅ **Visual Feedback**: Filter icon changes when active
22
+ - ✅ **Single Filter Open**: Only one filter dropdown can be open at a time
23
+ - ✅ **ESC Key Support**: Press ESC to close the open filter
24
+ - ✅ **Programmatic Control**: Clear filters programmatically using `clearFilter()` method
25
+ - ✅ **Type-Safe**: Fully typed with TypeScript
26
+ - ✅ **Standalone Component**: Works with Angular 14+ standalone components
27
+ - ✅ **Fully Customizable**: Configurable inputs for customization
28
+ - ✅ **Accessible**: ARIA labels and keyboard navigation support
29
+ - ✅ **Data Adaptive**: Simply update `columnKey` and `columnName` when your data changes
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install ngx-column-filter-popup
35
+ ```
36
+
37
+ **Note**: This package is published with TypeScript source files. Make sure your Angular project has TypeScript configured to compile these files.
38
+
39
+ ## Quick Start
40
+
41
+ ### Standalone Component (Angular 14+)
42
+
43
+ ```typescript
44
+ import { Component } from '@angular/core';
45
+ import { ColumnFilterComponent } from 'ngx-column-filter-popup';
46
+ import { FilterConfig, applyColumnFilter } from 'ngx-column-filter-popup';
47
+
48
+ @Component({
49
+ selector: 'app-example',
50
+ imports: [ColumnFilterComponent],
51
+ template: `
52
+ <lib-column-filter
53
+ columnName="first name"
54
+ columnKey="firstName"
55
+ (filterApplied)="onFilterApplied($event)"
56
+ (filterCleared)="onFilterCleared()">
57
+ </lib-column-filter>
58
+ `
59
+ })
60
+ export class ExampleComponent {
61
+ onFilterApplied(filterConfig: FilterConfig) {
62
+ console.log('Filter applied:', filterConfig);
63
+ // Apply filter to your data
64
+ }
65
+
66
+ onFilterCleared() {
67
+ console.log('Filter cleared');
68
+ // Clear filter from your data
69
+ }
70
+ }
71
+ ```
72
+
73
+ ### Module-Based (Optional)
74
+
75
+ ```typescript
76
+ import { NgModule } from '@angular/core';
77
+ import { ColumnFilterModule } from 'ngx-column-filter-popup';
78
+
79
+ @NgModule({
80
+ imports: [ColumnFilterModule],
81
+ // ...
82
+ })
83
+ export class YourModule {}
84
+ ```
85
+
86
+ ## Field Types
87
+
88
+ ### Text Field (Default)
89
+
90
+ ```html
91
+ <lib-column-filter
92
+ columnName="name"
93
+ columnKey="name"
94
+ fieldType="text"
95
+ (filterApplied)="onFilter($event)">
96
+ </lib-column-filter>
97
+ ```
98
+
99
+ ### Currency Field
100
+
101
+ ```html
102
+ <lib-column-filter
103
+ columnName="balance"
104
+ columnKey="balance"
105
+ fieldType="currency"
106
+ currencySymbol="$"
107
+ (filterApplied)="onBalanceFilter($event)">
108
+ </lib-column-filter>
109
+ ```
110
+
111
+ ### Age/Number Field
112
+
113
+ ```html
114
+ <lib-column-filter
115
+ columnName="age"
116
+ columnKey="age"
117
+ fieldType="age"
118
+ (filterApplied)="onAgeFilter($event)">
119
+ </lib-column-filter>
120
+ ```
121
+
122
+ ### Date Field
123
+
124
+ ```html
125
+ <lib-column-filter
126
+ columnName="date"
127
+ columnKey="date"
128
+ fieldType="date"
129
+ (filterApplied)="onDateFilter($event)">
130
+ </lib-column-filter>
131
+ ```
132
+
133
+ ### Status Field
134
+
135
+ ```html
136
+ <lib-column-filter
137
+ columnName="status"
138
+ columnKey="status"
139
+ fieldType="status"
140
+ [statusOptions]="['qualified', 'unqualified', 'negotiation', 'new']"
141
+ (filterApplied)="onStatusFilter($event)">
142
+ </lib-column-filter>
143
+ ```
144
+
145
+ ## API Reference
146
+
147
+ ### ColumnFilterComponent
148
+
149
+ #### Inputs
150
+
151
+ | Input | Type | Default | Description |
152
+ |-------|------|---------|-------------|
153
+ | `columnName` | `string` | `''` | Display name of the column (used in placeholder) |
154
+ | `columnKey` | `string` | `''` | Property name to filter on |
155
+ | `fieldType` | `FieldType` | `'text'` | Field type: 'text', 'currency', 'age', 'date', or 'status' |
156
+ | `currencySymbol` | `string` | `'$'` | Currency symbol for currency field type (optional) |
157
+ | `statusOptions` | `string[]` | `[]` | Array of status options for status field type (required for status) |
158
+ | `initialFilter` | `FilterConfig?` | `undefined` | Initial filter configuration (optional) |
159
+ | `placeholder` | `string?` | `undefined` | Custom placeholder text. Default: "Search by {columnName}" |
160
+ | `availableMatchTypes` | `MatchType[]?` | `undefined` | Customize available match types (optional) |
161
+
162
+ #### Outputs
163
+
164
+ | Output | Type | Description |
165
+ |--------|------|-------------|
166
+ | `filterApplied` | `EventEmitter<FilterConfig>` | Emitted when filter is applied |
167
+ | `filterCleared` | `EventEmitter<void>` | Emitted when filter is cleared |
168
+
169
+ #### Public Methods
170
+
171
+ | Method | Description |
172
+ |--------|-------------|
173
+ | `clearFilter()` | Programmatically clear all filter rules and reset the filter |
174
+
175
+ ### FilterConfig Interface
176
+
177
+ ```typescript
178
+ type FieldType = 'text' | 'currency' | 'age' | 'date' | 'status';
179
+
180
+ interface FilterConfig {
181
+ rules: FilterRule[];
182
+ globalMatchMode?: GlobalMatchMode; // 'match-all-rules' | 'match-any-rule'
183
+ fieldType?: FieldType;
184
+ statusOptions?: string[];
185
+ }
186
+
187
+ interface FilterRule {
188
+ id: string;
189
+ matchType: MatchType;
190
+ value: string;
191
+ }
192
+ ```
193
+
194
+ ### Utility Functions
195
+
196
+ #### applyColumnFilter
197
+
198
+ Apply filter rules to a dataset:
199
+
200
+ ```typescript
201
+ import { applyColumnFilter } from 'ngx-column-filter-popup';
202
+
203
+ const filteredData = applyColumnFilter(
204
+ data,
205
+ 'columnKey',
206
+ filterConfig
207
+ );
208
+ ```
209
+
210
+ #### itemMatchesFilter
211
+
212
+ Check if a single item matches filter rules:
213
+
214
+ ```typescript
215
+ import { itemMatchesFilter } from 'ngx-column-filter-popup';
216
+
217
+ const matches = itemMatchesFilter(
218
+ item,
219
+ 'columnKey',
220
+ filterConfig
221
+ );
222
+ ```
223
+
224
+ ## Programmatic Control
225
+
226
+ ### Clearing Filters Programmatically
227
+
228
+ ```typescript
229
+ import { Component, ViewChild } from '@angular/core';
230
+ import { ColumnFilterComponent } from 'ngx-column-filter-popup';
231
+
232
+ @Component({
233
+ template: `
234
+ <lib-column-filter
235
+ #nameFilter
236
+ columnName="name"
237
+ columnKey="name">
238
+ </lib-column-filter>
239
+ <button (click)="clearFilter()">Clear Filter</button>
240
+ `
241
+ })
242
+ export class ExampleComponent {
243
+ @ViewChild('nameFilter') filter!: ColumnFilterComponent;
244
+
245
+ clearFilter() {
246
+ this.filter.clearFilter(); // Programmatically clear the filter
247
+ }
248
+ }
249
+ ```
250
+
251
+ ## Complete Example
252
+
253
+ ```typescript
254
+ import { Component } from '@angular/core';
255
+ import { ColumnFilterComponent } from 'ngx-column-filter-popup';
256
+ import { FilterConfig, applyColumnFilter } from 'ngx-column-filter-popup';
257
+
258
+ interface User {
259
+ id: number;
260
+ firstName: string;
261
+ lastName: string;
262
+ email: string;
263
+ age: number;
264
+ balance: number;
265
+ joinDate: string;
266
+ status: string;
267
+ }
268
+
269
+ @Component({
270
+ selector: 'app-user-list',
271
+ imports: [ColumnFilterComponent],
272
+ template: `
273
+ <table>
274
+ <thead>
275
+ <tr>
276
+ <th>
277
+ First Name
278
+ <lib-column-filter
279
+ columnName="first name"
280
+ columnKey="firstName"
281
+ (filterApplied)="onFirstNameFilter($event)"
282
+ (filterCleared)="onFirstNameClear()">
283
+ </lib-column-filter>
284
+ </th>
285
+ <th>
286
+ Age
287
+ <lib-column-filter
288
+ columnName="age"
289
+ columnKey="age"
290
+ fieldType="age"
291
+ (filterApplied)="onAgeFilter($event)">
292
+ </lib-column-filter>
293
+ </th>
294
+ <th>
295
+ Balance
296
+ <lib-column-filter
297
+ columnName="balance"
298
+ columnKey="balance"
299
+ fieldType="currency"
300
+ currencySymbol="$"
301
+ (filterApplied)="onBalanceFilter($event)">
302
+ </lib-column-filter>
303
+ </th>
304
+ <th>
305
+ Join Date
306
+ <lib-column-filter
307
+ columnName="join date"
308
+ columnKey="joinDate"
309
+ fieldType="date"
310
+ (filterApplied)="onDateFilter($event)">
311
+ </lib-column-filter>
312
+ </th>
313
+ <th>
314
+ Status
315
+ <lib-column-filter
316
+ columnName="status"
317
+ columnKey="status"
318
+ fieldType="status"
319
+ [statusOptions]="statusOptions"
320
+ (filterApplied)="onStatusFilter($event)">
321
+ </lib-column-filter>
322
+ </th>
323
+ </tr>
324
+ </thead>
325
+ <tbody>
326
+ <tr *ngFor="let user of filteredUsers">
327
+ <td>{{ user.firstName }}</td>
328
+ <td>{{ user.age }}</td>
329
+ <td>${{ user.balance }}</td>
330
+ <td>{{ user.joinDate }}</td>
331
+ <td>{{ user.status }}</td>
332
+ </tr>
333
+ </tbody>
334
+ </table>
335
+ `
336
+ })
337
+ export class UserListComponent {
338
+ users: User[] = [
339
+ { id: 1, firstName: 'John', lastName: 'Doe', email: 'john@example.com', age: 30, balance: 50000, joinDate: '2020-01-15', status: 'active' }
340
+ ];
341
+
342
+ filteredUsers: User[] = [...this.users];
343
+ statusOptions = ['active', 'inactive', 'on-leave'];
344
+
345
+ firstNameFilter: FilterConfig | null = null;
346
+ ageFilter: FilterConfig | null = null;
347
+ balanceFilter: FilterConfig | null = null;
348
+ dateFilter: FilterConfig | null = null;
349
+ statusFilter: FilterConfig | null = null;
350
+
351
+ onFirstNameFilter(filterConfig: FilterConfig) {
352
+ this.firstNameFilter = filterConfig;
353
+ this.applyAllFilters();
354
+ }
355
+
356
+ onFirstNameClear() {
357
+ this.firstNameFilter = null;
358
+ this.applyAllFilters();
359
+ }
360
+
361
+ onAgeFilter(filterConfig: FilterConfig) {
362
+ this.ageFilter = filterConfig;
363
+ this.applyAllFilters();
364
+ }
365
+
366
+ onBalanceFilter(filterConfig: FilterConfig) {
367
+ this.balanceFilter = filterConfig;
368
+ this.applyAllFilters();
369
+ }
370
+
371
+ onDateFilter(filterConfig: FilterConfig) {
372
+ this.dateFilter = filterConfig;
373
+ this.applyAllFilters();
374
+ }
375
+
376
+ onStatusFilter(filterConfig: FilterConfig) {
377
+ this.statusFilter = filterConfig;
378
+ this.applyAllFilters();
379
+ }
380
+
381
+ private applyAllFilters() {
382
+ let result = [...this.users];
383
+
384
+ if (this.firstNameFilter) {
385
+ result = applyColumnFilter(result, 'firstName', this.firstNameFilter);
386
+ }
387
+ if (this.ageFilter) {
388
+ result = applyColumnFilter(result, 'age', this.ageFilter);
389
+ }
390
+ if (this.balanceFilter) {
391
+ result = applyColumnFilter(result, 'balance', this.balanceFilter);
392
+ }
393
+ if (this.dateFilter) {
394
+ result = applyColumnFilter(result, 'joinDate', this.dateFilter);
395
+ }
396
+ if (this.statusFilter) {
397
+ result = applyColumnFilter(result, 'status', this.statusFilter);
398
+ }
399
+
400
+ this.filteredUsers = result;
401
+ }
402
+ }
403
+ ```
404
+
405
+ ## Documentation
406
+
407
+ For comprehensive documentation including:
408
+ - Detailed usage examples
409
+ - How to adapt to different data structures
410
+ - Match All Rules feature explanation
411
+ - Complete API reference
412
+ - Troubleshooting guide
413
+
414
+ See [DOCUMENTATION.md](./DOCUMENTATION.md)
415
+
416
+ For programmatic control examples, see [USAGE_EXAMPLES.md](./USAGE_EXAMPLES.md)
417
+
418
+ ## Styling
419
+
420
+ The component uses SCSS and includes default styles. You can customize the appearance by overriding CSS classes:
421
+
422
+ - `.column-filter-wrapper` - Main wrapper
423
+ - `.filter-trigger` - Filter button
424
+ - `.filter-dropdown` - Dropdown container
425
+ - `.filter-rule` - Individual filter rule
426
+ - `.btn-apply` - Apply button
427
+ - `.btn-clear` - Clear button
428
+
429
+ ## Browser Support
430
+
431
+ - Chrome (latest)
432
+ - Firefox (latest)
433
+ - Safari (latest)
434
+ - Edge (latest)
435
+
436
+ ## Requirements
437
+
438
+ - Angular 14+
439
+ - TypeScript 4.7+
440
+
441
+ ## License
442
+
443
+ MIT
444
+
445
+ ## Author
446
+
447
+ Made with ❤️ by Shivam Sharma
448
+
449
+ ## Contributing
450
+
451
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,251 @@
1
+ # Column Filter Library - Usage Examples
2
+
3
+ ## 1. Clear Filter as Exported Function
4
+
5
+ You can call the `clearFilter()` method programmatically from any component:
6
+
7
+ ### Using ViewChild:
8
+
9
+ ```typescript
10
+ import { Component, ViewChild } from '@angular/core';
11
+ import { ColumnFilterComponent } from 'ngx-column-filter-popup';
12
+
13
+ @Component({
14
+ selector: 'app-example',
15
+ template: `
16
+ <table>
17
+ <thead>
18
+ <tr>
19
+ <th>
20
+ Name
21
+ <lib-column-filter
22
+ #nameFilter
23
+ columnName="name"
24
+ columnKey="name"
25
+ (filterApplied)="onFilter($event)">
26
+ </lib-column-filter>
27
+ </th>
28
+ </tr>
29
+ </thead>
30
+ </table>
31
+
32
+ <button (click)="clearNameFilter()">Clear Name Filter</button>
33
+ `
34
+ })
35
+ export class ExampleComponent {
36
+ @ViewChild('nameFilter') nameFilter!: ColumnFilterComponent;
37
+
38
+ clearNameFilter() {
39
+ // Programmatically clear the filter
40
+ this.nameFilter.clearFilter();
41
+ }
42
+
43
+ onFilter(filterConfig: FilterConfig) {
44
+ // Handle filter applied
45
+ }
46
+ }
47
+ ```
48
+
49
+ ### Using Multiple Filters:
50
+
51
+ ```typescript
52
+ import { Component, ViewChildren, QueryList } from '@angular/core';
53
+ import { ColumnFilterComponent } from 'ngx-column-filter-popup';
54
+
55
+ @Component({
56
+ selector: 'app-example',
57
+ template: `
58
+ <table>
59
+ <thead>
60
+ <tr>
61
+ <th>
62
+ First Name
63
+ <lib-column-filter
64
+ #firstNameFilter
65
+ columnName="first name"
66
+ columnKey="firstName">
67
+ </lib-column-filter>
68
+ </th>
69
+ <th>
70
+ Last Name
71
+ <lib-column-filter
72
+ #lastNameFilter
73
+ columnName="last name"
74
+ columnKey="lastName">
75
+ </lib-column-filter>
76
+ </th>
77
+ </tr>
78
+ </thead>
79
+ </table>
80
+
81
+ <button (click)="clearAllFilters()">Clear All Filters</button>
82
+ `
83
+ })
84
+ export class ExampleComponent {
85
+ @ViewChildren(ColumnFilterComponent) filters!: QueryList<ColumnFilterComponent>;
86
+
87
+ clearAllFilters() {
88
+ // Clear all filters programmatically
89
+ this.filters.forEach(filter => {
90
+ filter.clearFilter();
91
+ });
92
+ }
93
+ }
94
+ ```
95
+
96
+ ---
97
+
98
+ ## 2. Only One Column Filter Open at a Time
99
+
100
+ This feature is automatically enabled. When you open one filter, others will automatically close.
101
+
102
+ **No additional code needed!** This works automatically.
103
+
104
+ Example:
105
+ - First Name filter is open
106
+ - User opens Last Name filter
107
+ - First Name filter automatically closes
108
+
109
+ ---
110
+
111
+ ## 3. ESC Key Support
112
+
113
+ Pressing the ESC key will automatically close the open filter.
114
+
115
+ **No additional code needed!** This works automatically.
116
+
117
+ ### How it works:
118
+ 1. User opens filter dropdown
119
+ 2. User presses ESC key
120
+ 3. Filter dropdown automatically closes
121
+
122
+ ---
123
+
124
+ ## Complete Example
125
+
126
+ ```typescript
127
+ import { Component, ViewChild, ViewChildren, QueryList } from '@angular/core';
128
+ import { ColumnFilterComponent } from 'ngx-column-filter-popup';
129
+ import { FilterConfig, applyColumnFilter } from 'ngx-column-filter-popup';
130
+
131
+ interface User {
132
+ id: number;
133
+ firstName: string;
134
+ lastName: string;
135
+ email: string;
136
+ }
137
+
138
+ @Component({
139
+ selector: 'app-user-list',
140
+ imports: [ColumnFilterComponent],
141
+ template: `
142
+ <div>
143
+ <button (click)="clearFirstNameFilter()">Clear First Name Filter</button>
144
+ <button (click)="clearAllFilters()">Clear All Filters</button>
145
+ </div>
146
+
147
+ <table>
148
+ <thead>
149
+ <tr>
150
+ <th>
151
+ First Name
152
+ <lib-column-filter
153
+ #firstNameFilter
154
+ columnName="first name"
155
+ columnKey="firstName"
156
+ (filterApplied)="onFirstNameFilter($event)"
157
+ (filterCleared)="onFirstNameClear()">
158
+ </lib-column-filter>
159
+ </th>
160
+ <th>
161
+ Last Name
162
+ <lib-column-filter
163
+ #lastNameFilter
164
+ columnName="last name"
165
+ columnKey="lastName"
166
+ (filterApplied)="onLastNameFilter($event)">
167
+ </lib-column-filter>
168
+ </th>
169
+ </tr>
170
+ </thead>
171
+ <tbody>
172
+ <tr *ngFor="let user of filteredUsers">
173
+ <td>{{ user.firstName }}</td>
174
+ <td>{{ user.lastName }}</td>
175
+ </tr>
176
+ </tbody>
177
+ </table>
178
+ `
179
+ })
180
+ export class UserListComponent {
181
+ users: User[] = [
182
+ { id: 1, firstName: 'John', lastName: 'Doe', email: 'john@example.com' },
183
+ { id: 2, firstName: 'Jane', lastName: 'Smith', email: 'jane@example.com' }
184
+ ];
185
+
186
+ filteredUsers: User[] = [...this.users];
187
+ firstNameFilter: FilterConfig | null = null;
188
+ lastNameFilter: FilterConfig | null = null;
189
+
190
+ // Using ViewChild for single filter
191
+ @ViewChild('firstNameFilter') firstNameFilterComponent!: ColumnFilterComponent;
192
+
193
+ // Using ViewChildren for multiple filters
194
+ @ViewChildren(ColumnFilterComponent) allFilters!: QueryList<ColumnFilterComponent>;
195
+
196
+ // Clear single filter programmatically
197
+ clearFirstNameFilter() {
198
+ this.firstNameFilterComponent.clearFilter();
199
+ }
200
+
201
+ // Clear all filters programmatically
202
+ clearAllFilters() {
203
+ this.allFilters.forEach(filter => {
204
+ filter.clearFilter();
205
+ });
206
+ // Also clear filter configs
207
+ this.firstNameFilter = null;
208
+ this.lastNameFilter = null;
209
+ this.filteredUsers = [...this.users];
210
+ }
211
+
212
+ onFirstNameFilter(filterConfig: FilterConfig) {
213
+ this.firstNameFilter = filterConfig;
214
+ this.applyFilters();
215
+ }
216
+
217
+ onFirstNameClear() {
218
+ this.firstNameFilter = null;
219
+ this.applyFilters();
220
+ }
221
+
222
+ onLastNameFilter(filterConfig: FilterConfig) {
223
+ this.lastNameFilter = filterConfig;
224
+ this.applyFilters();
225
+ }
226
+
227
+ private applyFilters() {
228
+ let result = [...this.users];
229
+
230
+ if (this.firstNameFilter) {
231
+ result = applyColumnFilter(result, 'firstName', this.firstNameFilter);
232
+ }
233
+
234
+ if (this.lastNameFilter) {
235
+ result = applyColumnFilter(result, 'lastName', this.lastNameFilter);
236
+ }
237
+
238
+ this.filteredUsers = result;
239
+ }
240
+ }
241
+ ```
242
+
243
+ ---
244
+
245
+ ## Features Summary
246
+
247
+ ✅ **Clear Filter Programmatically**: Call `clearFilter()` method
248
+ ✅ **Only One Filter Open**: Automatically handled
249
+ ✅ **ESC Key Support**: Automatically handled
250
+
251
+ **All features work automatically - no additional configuration needed!**