-
Notifications
You must be signed in to change notification settings - Fork 6.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Table] - Add example with multiple filtering columns #6178
Comments
@andrewseguin I haven't come across any examples on how to accomplish this yet... any leads? |
This shows two separate text filters, but the concept would be the same for selects, checkboxes, etc. https://plnkr.co/edit/oQOYQgW0vCx8tfAgb1w9?p=preview EDIT: and here's a version filtering with a slider |
thanks! this has helped me sort out my issue, I couldn't tell from the sample code that it was just a filter in a filter, but the code in that plunker you sent is well formatted, I could easily understand it. Thanks again |
Hi, actually the mat(cdk)-table doesn't seem to be as flexible as promised. Regards, |
@nickwinger ,
|
@spanja |
My bad I misunderstood, I thought you wanted a second row in the header instead of a second header. |
trying to implement multiple columns filtering using the filterPredicate. The limitation i saw when trying to perform filtering on multiple columns is that the "this" pointer is that of the MatTableDataSource and not that of my component. if the filterPredicate pass back the context of my component, then i can have a simpler solution. At this point, the work around is have a form based input to accept search values for each column or to have another table above the main mat-table. |
solve it! woot!!! i ended up rolling my own filter function. Sharing my poc. hope this is useful to others.
Updated: I also styled the two css elements; "eps-footer-row" and "eps-footer-cell". no magic here, just background colors and color |
I also did it this way now as a workaround, but it is not perfect when it comes to horizontal scrolling and responsivness. |
interesting to see why u need the horizontal scrolling. what is your requirement? pls share a simplified view , maybe we can input some ideas |
Why i need horizontal scrolling ? |
from a technical solution, yes, the horizontal scrolling would be do fine. |
Lol, my UX expert says the same, but he agreed with me:
Cheers from a non UX expert ;-D |
first question: why do women hate white socks? hahahahha. i am curious. :p maybe a suggestion back to the developers of this group that we can do it via an option e.g.
very good suggestion. (Y) |
@erickyi2006 I am using |
tnx @irowbin , good demo u got there. looks v configurable. well done. is there a question for me? |
Wonderful, @irowbin! Could you provide some sort of example with mat-select in md-table' header? |
@astra1 here is some snippet from my code: <!-- repeat this to all columns -->
<ng-container cdkColumnDef="Column1">
<mat-header-cell *cdkHeaderCellDef>
<!-- instead of adding mat-sort-header directive to the mat-header-cell, i've move it on span tag to separate sorting and filtering icon .-->
<span mat-sort-header>Column1 </span>
<!-- i've applied css rules to the icon-->
<span (click)="onFilterClick('col1')" class="filter-icon">
<mat-icon>keyboard_arrow_down</mat-icon>
</span>
<filter-template [openFilter]="true" *ngIf="templateFor === 'col1' "></filter-template>
</mat-header-cell>
<mat-cell *cdkCellDef="let row">{{row.Column1}}</mat-cell>
</ng-container> // mat-table component.ts
onFilterClick(templateFor:string){
this.templateFor = templateFor;
}
// inside the filter-template component.ts
@ViewChild('filterMenu') triggerMenu: MatMenuTrigger;
@Input() openFilter: boolean;
ngOnChanges(){
if(this.openFilter) {
this.triggerMenu.openMenu()
}
} <!-- filter-template component.html -->
<span #filterMenu="matMenuTrigger" [matMenuTriggerFor]="menu" id="filter-panel">
<mat-menu #menu="matMenu" [overlapTrigger]="false">
<div (click)="$event.stopPropagation()" (keyup)="$event.stopPropagation()" (keydown)="$event.stopPropagation()">
<form autocomplete="off" (ngSubmit)="onFilterSubmit()" [formGroup]="filterForm">
<mat-form-field style="width: auto;">
<mat-select formControlName="op" placeholder="Condition:">
<mat-option *ngFor="let con of conditions" [value]="condi.id">
{{con.text}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="!forFirstValue">
<input formControlName="val1" matInput placeholder="Value">
</mat-form-field>
<mat-form-field class="font-sm" *ngIf="forSecondValue">
<input formControlName="val2" matInput placeholder="Second Value">
</mat-form-field>
<button [disabled]="hasNoValue" matRipple type="submit"></button>
</form>
</div>
</mat-menu>
</span> I hope you'll get some clue from this snippet. 😆 |
thanks to @irowbin . I do miss something, get an ERROR TypeError: Cannot read property 'templateRef' of undefined. |
@patrickschlaepfer I think i have no idea of your exception! 🤣 |
@irowbin I also get cannot read property of 'templateRef' of undefined. From what I can tell the html bit <filter-template [openFilter]="true" ... needs to have some sort of templateRef passed to it |
didn't try but i think typo is here missing single quote in col1 |
@irowbin any chance we can get a stackblitz for the gif you shared? |
stackblitz would be great! |
Building on-top of what @alexisdoualle has given for a per-column filtering solution I would like to add in how I managed to fit my filter inputs inside of my table column headers instead of else-where on the page. Also not have them trigger column sorting when they are focused for input. I'd like to preface with saying this is just a proof of concept and small snippet, I hope it helps though! <ng-container *ngFor="let column of displayedColumns" matColumnDef="{{column}}">
<mat-header-cell *matHeaderCellDef>
<span mat-sort-header>{{column | uppercase}}</span>
<input class="filter-input" matInput (keyup)="applyFilter(column, $event.target.value)" placeholder="Filter {{column}}" />
</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row[column]}}</mat-cell>
</ng-container> If you are NOT using mat-sort functionality then the trick is simple, just include your filter input inside of the mat-header-cell. |
Is it possible to have it both ways? I mean filtering on the full table and per column? I don't see how to do it after modifying the filterPredicate. Anyone? |
@alexisdoualle 's solution worked for me.But I still can't figure out a way to retain the default filter once |
@kal93 @jordanA29 https://stackblitz.com/edit/angular-hbakxo-xctfqy?file=app/table-filtering-example.ts This lets you have individual filters for each column and a top-level filter for all columns (which you can test with the value '999') The trick was adding a property to the stringified object (.topFilter), which when set to true (by the top-level form control) will make the custom predicate function use the OR operator, so that every field is parsed, like in the default predicate. customFilterPredicate() {
const myFilterPredicate = function(data:PeriodicElement, filter:string) :boolean {
let searchString = JSON.parse(filter);
let nameFound = data.name.toString().trim().toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1
let positionFound = data.position.toString().trim().indexOf(searchString.position) !== -1
if (searchString.topFilter) {
return nameFound || positionFound
} else {
return nameFound && positionFound
}
}
return myFilterPredicate;
} Of course, if you want all columns to be parsed (like 'weight' and 'symbol'), you need to add them to the code, either explicitly, or by looping through the 'data' parameter's properties. |
Hey Do you have any example how we can achieve same functionality of filter on each column using dynamic data? Thank you |
Hey Do you have any example how we can achieve same functionality of filter on each column using dynamic data? Thank you |
@irowbin i required this feature, i have copied whole code but when i select value from select , it prevent selecting value due to event.stopPropagation(). I did not get any help |
@Rashid75 That was to prevent closing the matMenu while firing other events inside the matMenu. Maybe you just forgot to wrap with form group to get changed values of form control? <div [formGroup]="filterForm"> <!-- i think you missed this line -->
<input formControlName="filterValue" type="text" />
</div> |
@irowbin I have wrapped it with formGroup but did not work, Any working code snippet ? I am stuck on it since last week |
@Rashid75 here is a working example of just to test the values: |
Here working example. I was trying implement angular material chip on filter text when user press enter. Now I'm having issue. Can anyone help on this? *First filter working good as expected |
@samuelkavin That stackblitz link is 404 not found. |
@irowbin would you mind sharing the code from the demo you posted? That is exactly what i need right now and im not getting it to work on my end. |
@samuelkavin can you post link again. Your stackblitz link isnt working. |
I have answered about this topic and create a repo explain how I did it Filtering different columns in a material table |
Explanation on the thinking process: I developped a solution for this problem using Mat Menu and Dynamic component injection. The main goal is to define the settings of the table through this structure type: settingList = [
{ columnName: 'position', filterMode: FilterMode.NUMBER_MODE },
{ columnName: 'name', filterMode: FilterMode.TEXT_MODE },
{ columnName: 'weight', filterMode: FilterMode.NUMBER_MODE },
{ columnName: 'symbol', filterMode: FilterMode.TEXT_MODE },
{ columnName: 'date', filterMode: FilterMode.DATE_MODE },
]; It is the main reason why I inject my filter dynamically. All filter follows this 'interface' to satisfy a common behaviour: export class FilterImplementation {
@Input() columnName: string;
@Output() predicateEmitter = new EventEmitter<ColumnPredicate>();
} The principle is to have a generic Mat Menu that returns a export class ColumnPredicate {
name: string;
predicate: (value:string) => boolean;
} Next, you need to switch the filterPredicate based on the current filter triggered by the Mat Menu. applyFilter(columnPredicate: ColumnPredicate) {
const newPredicate = (data: PeriodicElement, notUsedParameter: string) => {
return columnPredicate.predicate.call(undefined, data[columnPredicate.name]);
}
this.dataSource.filterPredicate = TableFilteredComponent.composePredicateAnd(this.dataSource.filterPredicate, newPredicate);
this.dataSource.filter = 'useless trigger'; // Triggering filter (It is a little bit of hacking but hey, angular material not so flexible after all)
}
static composePredicateAnd(materialPredicate: (data, value) => boolean, filterPredicate: (data, value) => boolean) {
return (data, value) => materialPredicate.call(undefined, data, value) && filterPredicate.call(undefined, data, value);
} To sum up the flow of this filter table: I would love to have a method on dataSource with the signature Note that this is a prototype that I will continue to improve. Feel free to give your opinion about it and to point out any problem you have using it. |
Improved @alexisdoualle by allowing unlimited count of provided object keys and values and no need to know them by names: |
@irowbin Can you please help me. I used your exact code even with the same dataSource but i am getting error as ERROR TypeError: filter.trim is not a function in Function at line this.dataSource.filter = searchFilter; Can you plz plz help me |
// the datasource filter expect string instead of object here.
this.dataSource.filter = searchFilter;
// change as
this.dataSource.filter = 'term'; |
Closing since we do not expect to provide an example for this. If you are managing your own DataSource, handling multiple filters should be implemented by simply using your provided inputs to produce a new list of data to emit onto the observable |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Bug, feature request, or proposal:
Proposal.
What is the expected behavior?
It would be good to see an example showing multiple filters (in this case inputs/selects) to filter rows/cells in md-table.
You can see this as an example.
What is the current behavior?
Currently the filter example just shows how to filter multiple columns by a single input.
The text was updated successfully, but these errors were encountered: