https://github.com/kakarotx10/ngx-column-filter
A powerful, reusable Angular column filter component with support for multiple field types, advanced filtering rules, and customizable match modes.
https://github.com/kakarotx10/ngx-column-filter
Last synced: 5 months ago
JSON representation
A powerful, reusable Angular column filter component with support for multiple field types, advanced filtering rules, and customizable match modes.
- Host: GitHub
- URL: https://github.com/kakarotx10/ngx-column-filter
- Owner: kakarotx10
- License: mit
- Created: 2026-01-12T16:11:06.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-01-12T16:43:18.000Z (5 months ago)
- Last Synced: 2026-01-12T22:10:26.021Z (5 months ago)
- Language: TypeScript
- Size: 96.7 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-angular - ngx-column-filter - A powerful, reusable Angular column filter component with support for multiple field types, advanced filtering rules, and customizable match modes. (Third Party Components / Data Grids)
- fucking-awesome-angular - ngx-column-filter - A powerful, reusable Angular column filter component with support for multiple field types, advanced filtering rules, and customizable match modes. (Third Party Components / Data Grids)
README
# Column Filter Library
A powerful, reusable Angular column filter component with support for multiple field types, advanced filtering rules, and customizable match modes.
[](https://www.npmjs.com/package/ngx-column-filter-popup)
[](https://opensource.org/licenses/MIT)
[](https://github.com/kakarotx10/ngx-column-filter)
[](https://github.com/kakarotx10/ngx-column-filter)
## 🚀 Quick Links
- 🎯 [Live Demo](https://ngx-column-filter.netlify.app/) - See it in action!
- 📦 [NPM Package](https://www.npmjs.com/package/ngx-column-filter-popup)
- 🏠 [GitHub Repository](https://github.com/kakarotx10/ngx-column-filter)
## 📚 Documentation & Guides
**New to this library?** Start here:
- 📖 **[Getting Started Tutorial](./GETTING_STARTED.md)** ⭐ - **Complete step-by-step guide: How to install, import, and use**
- Installation steps
- TypeScript imports explained
- Basic and advanced examples
- All field types with code samples
- Data filtering implementation
- Troubleshooting guide
**More Resources:**
- 📘 [Complete Documentation](./DOCUMENTATION.md) - Full API reference, all features explained
- 💡 [Usage Examples](./USAGE_EXAMPLES.md) - Advanced usage patterns and programmatic control
- 🚀 [Deployment Guide](./DEPLOYMENT.md) - How to deploy your Angular app
## 🐛 Support
- 🐛 [Report Bug](https://github.com/kakarotx10/ngx-column-filter/issues)
- 💬 [Request Feature](https://github.com/kakarotx10/ngx-column-filter/issues)
## Features
- ✅ **Multiple Filter Rules**: Add multiple filter conditions per column
- ✅ **Multiple Field Types**: Specialized filters for different data types
- **Text** - Text fields (default)
- **Currency** - Currency values with symbol support
- **Age/Number** - Numeric values
- **Date** - Date values with date picker
- **Status** - Predefined status options dropdown
- ✅ **Global Match Mode**: Choose how to combine multiple rules
- **Match All Rules** (AND Logic): All rules must match
- **Match Any Rule** (OR Logic): Any rule can match (default)
- ✅ **Various Match Types**: Different matching options based on field type
- ✅ **Visual Feedback**: Blinking red filter icon with X mark when active - clearly indicates applied filters
- ✅ **Backend Mode**: Send filter payloads directly to your backend API instead of filtering locally
- ✅ **Single/Multiple Rules**: Control whether users can add multiple filter rules with `allowMultipleRules` option
- ✅ **Single Filter Open**: Only one filter dropdown can be open at a time
- ✅ **ESC Key Support**: Press ESC to close the open filter
- ✅ **Programmatic Control**: Clear filters programmatically using `clearFilter()` method
- ✅ **Type-Safe**: Fully typed with TypeScript
- ✅ **Standalone Component**: Works with Angular 14+ standalone components
- ✅ **Fully Customizable**: Configurable inputs for customization
- ✅ **Accessible**: ARIA labels and keyboard navigation support
- ✅ **Data Adaptive**: Simply update `columnKey` and `columnName` when your data changes
## Installation
```bash
npm install ngx-column-filter-popup
```
**Note**: This package is published with TypeScript source files. Make sure your Angular project has TypeScript configured to compile these files.
> 💡 **New to this library?** Check out the **[Getting Started Tutorial](./GETTING_STARTED.md)** for a complete step-by-step guide with examples!
## Quick Start
### Standalone Component (Angular 14+)
#### Basic Example:
```typescript
import { Component } from '@angular/core';
import { ColumnFilterComponent } from 'ngx-column-filter-popup';
import { FilterConfig, applyColumnFilter } from 'ngx-column-filter-popup';
@Component({
selector: 'app-example',
imports: [ColumnFilterComponent],
template: `
`
})
export class ExampleComponent {
onFilterApplied(filterConfig: FilterConfig) {
console.log('Filter applied:', filterConfig);
// Apply filter to your data
}
onFilterCleared() {
console.log('Filter cleared');
// Clear filter from your data
}
}
```
#### Complete Example with New Features (Backend Mode, allowMultipleRules):
```typescript
import { Component, ViewChildren, QueryList } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ColumnFilterComponent } from 'ngx-column-filter-popup';
import { FilterConfig, applyColumnFilter } from 'ngx-column-filter-popup';
interface User {
id: number;
firstName: string;
lastName: string;
email: string;
}
@Component({
selector: 'app-example',
imports: [CommonModule, ColumnFilterComponent],
template: `
First Name
Last Name
Email
{{ user.firstName }}
{{ user.lastName }}
{{ user.email }}
Clear All Filters
`
})
export class ExampleComponent {
originalData: User[] = [
{ id: 1, firstName: 'John', lastName: 'Doe', email: 'john@example.com' }
];
filteredData: User[] = [...this.originalData];
// ✅ Unified filter storage - single source of truth
filters = new Map();
// ✅ Configuration: Which columns use backend mode
readonly backendModeColumns = new Set(['firstName', 'email']);
@ViewChildren(ColumnFilterComponent) filterComponents!: QueryList;
// ✅ Generic filter handler - works for all columns
onFilterApplied(columnKey: string, filterConfig: FilterConfig) {
this.filters.set(columnKey, filterConfig);
if (this.isBackendMode(columnKey)) {
this.sendAllBackendFiltersToBackend();
}
this.applyAllFilters();
}
// ✅ Generic filter clear handler
onFilterCleared(columnKey: string) {
this.filters.set(columnKey, null);
if (this.isBackendMode(columnKey)) {
this.sendAllBackendFiltersToBackend();
}
this.applyAllFilters();
}
// ✅ Check if column uses backend mode
isBackendMode(columnKey: string): boolean {
return this.backendModeColumns.has(columnKey);
}
// ✅ Apply all filters - automatically skips backend mode columns
private applyAllFilters() {
let result = [...this.originalData];
this.filters.forEach((filterConfig, columnKey) => {
// Skip backend mode columns (handled by backend)
if (filterConfig && !this.isBackendMode(columnKey)) {
result = applyColumnFilter(result, columnKey, filterConfig);
}
});
this.filteredData = result;
}
// ✅ Clear all filters programmatically
clearAllFilters() {
this.filters.clear();
this.sendAllBackendFiltersToBackend();
this.filteredData = [...this.originalData];
// Clear UI state in all filter components (icons/inputs)
if (this.filterComponents) {
this.filterComponents.forEach((filter: ColumnFilterComponent) => {
filter.clearFilter();
});
}
}
// ✅ Send all backend filters to API
private sendAllBackendFiltersToBackend() {
const activeFilters: Array<{
field: string;
matchType: string;
value: string;
fieldType: string;
}> = [];
this.backendModeColumns.forEach(columnKey => {
const filterConfig = this.filters.get(columnKey);
if (filterConfig && filterConfig.rules.length > 0) {
filterConfig.rules.forEach(rule => {
if (rule.value && rule.value.trim() !== '') {
activeFilters.push({
field: columnKey,
matchType: rule.matchType,
value: rule.value.trim(),
fieldType: filterConfig.fieldType || 'text'
});
}
});
}
});
const payload = { activeFilters, count: activeFilters.length };
// Send to your backend API
console.log('Backend payload:', payload);
}
}
```
### Module-Based (Optional)
```typescript
import { NgModule } from '@angular/core';
import { ColumnFilterModule } from 'ngx-column-filter-popup';
@NgModule({
imports: [ColumnFilterModule],
// ...
})
export class YourModule {}
```
## Field Types
### Text Field (Default)
```html
```
### Currency Field
```html
```
### Age/Number Field
```html
```
### Date Field
```html
```
### Status Field
```html
```
> 💡 **Note**: All examples use generic handlers `onFilterApplied(columnKey, $event)` and `onFilterCleared(columnKey)` - no need for separate functions per filter!
## API Reference
### ColumnFilterComponent
#### Inputs
| Input | Type | Default | Description |
|-------|------|---------|-------------|
| `columnName` | `string` | `''` | Display name of the column (used in placeholder) |
| `columnKey` | `string` | `''` | Property name to filter on |
| `fieldType` | `FieldType` | `'text'` | Field type: 'text', 'currency', 'age', 'date', or 'status' |
| `currencySymbol` | `string` | `'$'` | Currency symbol for currency field type (optional) |
| `statusOptions` | `string[]` | `[]` | Array of status options for status field type (required for status) |
| `initialFilter` | `FilterConfig?` | `undefined` | Initial filter configuration (optional) |
| `placeholder` | `string?` | `undefined` | Custom placeholder text. Default: "Search by {columnName}" |
| `availableMatchTypes` | `MatchType[]?` | `undefined` | Customize available match types (optional) |
| `backendMode` | `boolean` | `false` | When true, component emits filter data for backend API instead of frontend filtering |
| `allowMultipleRules` | `boolean` | `true` | When false, hides Add/Remove Rule buttons (single rule only) |
#### Outputs
| Output | Type | Description |
|--------|------|-------------|
| `filterApplied` | `EventEmitter` | Emitted when filter is applied |
| `filterCleared` | `EventEmitter` | Emitted when filter is cleared |
#### Public Methods
| Method | Description |
|--------|-------------|
| `clearFilter()` | Programmatically clear all filter rules and reset the filter |
### FilterConfig Interface
```typescript
type FieldType = 'text' | 'currency' | 'age' | 'date' | 'status';
interface FilterConfig {
rules: FilterRule[];
globalMatchMode?: GlobalMatchMode; // 'match-all-rules' | 'match-any-rule'
fieldType?: FieldType;
statusOptions?: string[];
}
interface FilterRule {
id: string;
matchType: MatchType;
value: string;
}
```
### Utility Functions
#### applyColumnFilter
Apply filter rules to a dataset:
```typescript
import { applyColumnFilter } from 'ngx-column-filter-popup';
const filteredData = applyColumnFilter(
data,
'columnKey',
filterConfig
);
```
#### itemMatchesFilter
Check if a single item matches filter rules:
```typescript
import { itemMatchesFilter } from 'ngx-column-filter-popup';
const matches = itemMatchesFilter(
item,
'columnKey',
filterConfig
);
```
## Backend Mode (Backend API Integration)
When `backendMode` is enabled, the component collects filter data and emits it in a format ready for your backend API. No frontend filtering is applied.
### Backend Mode Example:
```typescript
import { Component } from '@angular/core';
import { ColumnFilterComponent } from 'ngx-column-filter-popup';
import { FilterConfig } from 'ngx-column-filter-popup';
@Component({
selector: 'app-example',
imports: [ColumnFilterComponent],
template: `
`
})
export class ExampleComponent {
filters = new Map();
readonly backendModeColumns = new Set(['firstName', 'email']);
onFilterApplied(columnKey: string, filterConfig: FilterConfig) {
this.filters.set(columnKey, filterConfig);
this.sendToBackend();
}
onFilterCleared(columnKey: string) {
this.filters.set(columnKey, null);
this.sendToBackend();
}
private sendToBackend() {
const activeFilters: Array<{
field: string;
matchType: string;
value: string;
fieldType: string;
}> = [];
this.backendModeColumns.forEach(columnKey => {
const filterConfig = this.filters.get(columnKey);
if (filterConfig && filterConfig.rules.length > 0) {
filterConfig.rules.forEach(rule => {
if (rule.value && rule.value.trim() !== '') {
activeFilters.push({
field: columnKey,
matchType: rule.matchType,
value: rule.value.trim(),
fieldType: filterConfig.fieldType || 'text'
});
}
});
}
});
const payload = {
activeFilters: activeFilters,
count: activeFilters.length
};
// Send to your backend API
// this.httpClient.post('/api/filters', payload).subscribe(...);
console.log('Backend payload:', payload);
}
}
```
### Backend Payload Format:
```json
{
"activeFilters": [
{
"field": "firstName",
"matchType": "contains",
"value": "John",
"fieldType": "text"
},
{
"field": "email",
"matchType": "contains",
"value": "example",
"fieldType": "text"
}
],
"count": 2
}
```
## Single Rule Mode (allowMultipleRules)
Control whether users can add multiple filter rules:
```html
```
**When `allowMultipleRules="false"`:**
- ✅ Add Rule button is hidden
- ✅ Remove Rule buttons are hidden
- ✅ Global Match Mode toggle is hidden
- ✅ Users can only use a single filter rule
**When `allowMultipleRules="true"` (default):**
- ✅ All features work normally
- ✅ Users can add multiple rules
- ✅ Match All/Match Any toggle is available
## Programmatic Control
### Clearing Filters Programmatically
```typescript
import { Component, ViewChild } from '@angular/core';
import { ColumnFilterComponent } from 'ngx-column-filter-popup';
@Component({
template: `
Clear Filter
`
})
export class ExampleComponent {
@ViewChild('nameFilter') filter!: ColumnFilterComponent;
clearFilter() {
this.filter.clearFilter(); // Programmatically clear the filter
}
}
```
## Complete Example
**✅ Modern Implementation using Generic Handlers (Recommended):**
```typescript
import { Component, ViewChildren, QueryList } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ColumnFilterComponent } from 'ngx-column-filter-popup';
import { FilterConfig, applyColumnFilter } from 'ngx-column-filter-popup';
interface User {
id: number;
firstName: string;
lastName: string;
email: string;
age: number;
balance: number;
joinDate: string;
status: string;
}
@Component({
selector: 'app-user-list',
imports: [CommonModule, ColumnFilterComponent],
template: `
Clear All Filters
First Name
Last Name
Email
Age
Balance
Join Date
Status
{{ user.firstName }}
{{ user.lastName }}
{{ user.email }}
{{ user.age }}
${{ user.balance }}
{{ user.joinDate }}
{{ user.status }}
`
})
export class UserListComponent {
users: User[] = [
{ id: 1, firstName: 'John', lastName: 'Doe', email: 'john@example.com', age: 30, balance: 50000, joinDate: '2020-01-15', status: 'active' }
];
filteredUsers: User[] = [...this.users];
statusOptions = ['active', 'inactive', 'on-leave'];
// ✅ Unified filter storage - single source of truth
filters = new Map();
// ✅ Configuration: Which columns use backend mode
readonly backendModeColumns = new Set(['firstName', 'email']);
@ViewChildren(ColumnFilterComponent) filterComponents!: QueryList;
// ✅ Generic filter handler - works for ALL columns (no separate functions needed!)
onFilterApplied(columnKey: string, filterConfig: FilterConfig): void {
this.filters.set(columnKey, filterConfig);
if (this.isBackendMode(columnKey)) {
this.sendAllBackendFiltersToBackend();
}
this.applyAllFilters();
}
// ✅ Generic filter clear handler - works for ALL columns
onFilterCleared(columnKey: string): void {
this.filters.set(columnKey, null);
if (this.isBackendMode(columnKey)) {
this.sendAllBackendFiltersToBackend();
}
this.applyAllFilters();
}
// ✅ Check if column uses backend mode
isBackendMode(columnKey: string): boolean {
return this.backendModeColumns.has(columnKey);
}
// ✅ Apply all filters - automatically skips backend mode columns
private applyAllFilters(): void {
let result = [...this.users];
this.filters.forEach((filterConfig, columnKey) => {
// Skip backend mode columns (handled by backend)
if (filterConfig && !this.isBackendMode(columnKey)) {
result = applyColumnFilter(result, columnKey, filterConfig);
}
});
this.filteredUsers = result;
}
// ✅ Clear all filters programmatically
clearAllFilters(): void {
this.filters.clear();
this.sendAllBackendFiltersToBackend();
this.filteredUsers = [...this.users];
// Clear UI state in all filter components (icons/inputs)
if (this.filterComponents) {
this.filterComponents.forEach((filter: ColumnFilterComponent) => {
filter.clearFilter();
});
}
}
// ✅ Send all backend filters to API
private sendAllBackendFiltersToBackend(): void {
const activeFilters: Array<{
field: string;
matchType: string;
value: string;
fieldType: string;
}> = [];
this.backendModeColumns.forEach(columnKey => {
const filterConfig = this.filters.get(columnKey);
if (filterConfig && filterConfig.rules.length > 0) {
filterConfig.rules.forEach(rule => {
if (rule.value && rule.value.trim() !== '') {
activeFilters.push({
field: columnKey,
matchType: rule.matchType,
value: rule.value.trim(),
fieldType: filterConfig.fieldType || 'text'
});
}
});
}
});
const payload = { activeFilters, count: activeFilters.length };
// Send to your backend API
console.log('Backend payload:', payload);
}
}
```
**✨ Key Benefits of This Approach:**
- ✅ **No separate functions per filter** - One `onFilterApplied()` handles all columns
- ✅ **Easy to add new filters** - Just add HTML, no new functions needed
- ✅ **Clean and maintainable** - Map-based storage, generic handlers
- ✅ **Backend mode support** - Configurable per column
- ✅ **Single source of truth** - All filters in one Map
## 📖 Documentation
### For Beginners:
- **[Getting Started Tutorial](./GETTING_STARTED.md)** - Step-by-step guide with examples
- What to import in TypeScript
- How to setup component
- Complete working examples
- Common patterns
### For Advanced Users:
- **[Complete Documentation](./DOCUMENTATION.md)** - Full API reference
- All inputs and outputs
- Utility functions
- Type definitions
- Match modes explained
- Data structure adaptation
- **[Usage Examples](./USAGE_EXAMPLES.md)** - Advanced patterns
- Programmatic filter control
- Multiple filters management
- Custom configurations
- **[Deployment Guide](./DEPLOYMENT.md)** - Deploy your Angular app
- GitHub Pages
- Vercel
- Netlify
- Firebase Hosting
## Styling
The component uses SCSS and includes default styles. You can customize the appearance by overriding CSS classes:
- `.column-filter-wrapper` - Main wrapper
- `.filter-trigger` - Filter button
- `.filter-dropdown` - Dropdown container
- `.filter-rule` - Individual filter rule
- `.btn-apply` - Apply button
- `.btn-clear` - Clear button
## Browser Support
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
## Requirements
- Angular 14+
- TypeScript 4.7+
## License
MIT
## Author
Made with ❤️ by Shivam Sharma
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.