Skip to content
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

Closed
dev054 opened this issue Jul 31, 2017 · 56 comments
Closed

[Table] - Add example with multiple filtering columns #6178

dev054 opened this issue Jul 31, 2017 · 56 comments
Assignees
Labels
area: material/table docs This issue is related to documentation P4 A relatively minor issue that is not relevant to core functions
Projects

Comments

@dev054
Copy link

dev054 commented Jul 31, 2017

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.

@andrewseguin andrewseguin self-assigned this Jul 31, 2017
@andrewseguin andrewseguin added docs This issue is related to documentation md-table labels Jul 31, 2017
@andrewseguin andrewseguin added the P4 A relatively minor issue that is not relevant to core functions label Sep 5, 2017
@mikeaxle
Copy link

@andrewseguin I haven't come across any examples on how to accomplish this yet... any leads?

@willshowell
Copy link
Contributor

willshowell commented Sep 27, 2017

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

https://plnkr.co/edit/KZChr8jw1XJCCeNiDmUj?p=preview

@mikeaxle
Copy link

mikeaxle commented Sep 27, 2017

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

@andrewseguin andrewseguin added this to Features in Table Oct 19, 2017
@andrewseguin andrewseguin moved this from Features to Docs in Table Oct 19, 2017
@nickwinger
Copy link

Hi,

actually the mat(cdk)-table doesn't seem to be as flexible as promised.
I want to have a second header-row above the normal header-row
where i can have text-input fields for filtering each column
This doesn't seem to be possible as of right now ?

Regards,
Nick

@rbleuse
Copy link

rbleuse commented Dec 21, 2017

@nickwinger ,
try this, this is working for me :

<ng-container matColumnDef="entity">
  <mat-header-cell *matHeaderCellDef>
    <div fxFlexFill>
      <span translate="front.monitoring.quarterly.entity"></span>
      <mat-form-field floatPlaceholder="never">
        <mat-icon matPrefix>search</mat-icon>
        <input matInput [formControl]="entityFilter">
      </mat-form-field>
    </div>
  </mat-header-cell>
  <mat-cell *matCellDef="let history">{{ history.entity }}</mat-cell>
</ng-container>

@nickwinger
Copy link

@spanja
i don't know what you are trying to tell me ?
Where is the "second" header row in here ??
This is only a filter header, actually i have the normal header with sorting also

@rbleuse
Copy link

rbleuse commented Dec 21, 2017

My bad I misunderstood, I thought you wanted a second row in the header instead of a second header.

@erickyi2006
Copy link

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.

@erickyi2006
Copy link

erickyi2006 commented Feb 1, 2018

solve it! woot!!!
first, as i said earlier, there is a limitation in the filteredPredicate, i tried to put in the component "this" pointer into each data item which solved my problem of accessing the "this" pointer inside the filterPredicate function. but still trying to manipulate this.dataSource.filteredData is too buggy.

i ended up rolling my own filter function.
the issue itself deals with a 2nd header. I solved it by putting a footer instead as this is our requirement. implementing another top header is similar.

Sharing my poc. hope this is useful to others.

  <mat-table [dataSource]="dataSource" matSort>
    <ng-container matColumnDef="f1">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Field 1 </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.f1}} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="f2">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Field 2</mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.f2}}</mat-cell>
    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns" ></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;">
    </mat-row>
  </mat-table>

  <div class="eps-footer-row mat-header-row" role="row">
    <div class="eps-footer-cell mat-header-cell mat-column-f1" role="columnheader">
        <input (keyup)="applyColumnFilter('f1', $event.target.value)" placeholder="search Field 1" />
    </div>
    <div class="eps-footer-cell mat-header-cell mat-column-f2" role="columnheader">
        <input (keyup)="applyColumnFilter('f2', $event.target.value)" placeholder="search Field 2" />
    </div>
  </div>

  <mat-paginator [pageSizeOptions]="[5, 25, 50, 100]"></mat-paginator>


Updated: I also styled the two css elements; "eps-footer-row" and "eps-footer-cell". no magic here, just background colors and color

@nickwinger
Copy link

nickwinger commented Feb 1, 2018

I also did it this way now as a workaround, but it is not perfect when it comes to horizontal scrolling and responsivness.
It is a hack and not a real second mat-header-row.

@erickyi2006
Copy link

interesting to see why u need the horizontal scrolling. what is your requirement? pls share a simplified view , maybe we can input some ideas

@nickwinger
Copy link

Why i need horizontal scrolling ?
If you want to display a lot of data columns, that just don't fit the browser width, what should happen ?
-> of course horizontal scrolling.
The mat-table should be flexible, it should of course support horizontal scrolling (like any data-table)
I have set minimum widths on different data-columns, so there appears a horizontal scrollbar...

@erickyi2006
Copy link

from a technical solution, yes, the horizontal scrolling would be do fine.
but .... my UX expert would strongly throw her eyes up :p
her usual analogy - u won't put more than 8 points in your powerpoint slides, so why would u put more than 8 columns.
no dispute on what u r trying to achieve. from a better UX, I agree with my UX expert. yr call

@nickwinger
Copy link

nickwinger commented Feb 15, 2018

Lol, my UX expert says the same, but he agreed with me:

  1. The Table should be so flexibel
  2. some heavy Data applications just have to support horizontal scrolling, not everything has to look super cool pretty. Sometime data visualization is just technical...
    Think of fixing the first 2 or 3 columns and then just scroll right to compare data...
    My argument, why do we support vertical scrolling then ?
    Why do woman hate white socks ?

Cheers from a non UX expert ;-D

@erickyi2006
Copy link

erickyi2006 commented Feb 18, 2018

first question: why do women hate white socks? hahahahha. i am curious. :p
btw, i do love your idea suggestion : "fixing the first 2 or 3 columns". I would love to see this feature implemented.

maybe a suggestion back to the developers of this group that we can do it via an option e.g.

        fixedColumns:   {
            leftColumns: [0,1] // fixed the first and 2nd column - zero index
            rightColumns: [0] // fixed the right hand 1st column
        }

very good suggestion. (Y)

@irowbin
Copy link

irowbin commented Feb 19, 2018

@erickyi2006 I am using mat-menu, mat-select, mat-input everywhere to meet my requirements for the mat-table like context menu, column filter etc;

For instance here is the gif:
video_001 1 1

@erickyi2006
Copy link

tnx @irowbin , good demo u got there. looks v configurable. well done. is there a question for me?

@astra1
Copy link

astra1 commented Mar 1, 2018

Wonderful, @irowbin! Could you provide some sort of example with mat-select in md-table' header?

@irowbin
Copy link

irowbin commented Mar 1, 2018

@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. 😆

@patrickschlaepfer
Copy link

thanks to @irowbin . I do miss something, get an ERROR TypeError: Cannot read property 'templateRef' of undefined.

@irowbin
Copy link

irowbin commented Mar 8, 2018

@patrickschlaepfer I think i have no idea of your exception! 🤣

@pjcoupe
Copy link

pjcoupe commented Mar 12, 2018

@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

@erickyi2006
Copy link

didn't try but i think typo is here
<filter-template [openFilter]="true" *ngIf="templateFor === 'col1">

missing single quote in col1

@kal93
Copy link

kal93 commented Jun 17, 2018

@irowbin any chance we can get a stackblitz for the gif you shared?

@p97z
Copy link

p97z commented Jun 19, 2018

stackblitz would be great!

@KMathisGit
Copy link

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.
If you are using mat-sort functionality then you will need to instead put your column heading text inside of a span and give that span the mat-sort-header class instead of the mat-header-cell.

Sample result:
image

@jordanA29
Copy link

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?

@kal93
Copy link

kal93 commented Aug 24, 2018

@alexisdoualle 's solution worked for me.But I still can't figure out a way to retain the default filter once filterPredicate is overriden.
StackBlitz
I'm for a way to filter on top of whatever data the column filters return.
Is this even possible after overriding filterPredicate

@alexisdoualle
Copy link

alexisdoualle commented Aug 25, 2018

@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.

@shemanifisher
Copy link

data.name.toString().trim().toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1

Hey Do you have any example how we can achieve same functionality of filter on each column using dynamic data? Thank you

@shemanifisher
Copy link

@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

@Rashid75
Copy link

@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. 😆

@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
Kindly help

@irowbin
Copy link

irowbin commented Sep 28, 2018

@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?
e.g.

<div [formGroup]="filterForm"> <!-- i think you missed this line -->
    <input formControlName="filterValue" type="text" />
</div>

@Rashid75
Copy link

Rashid75 commented Oct 1, 2018

@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?
e.g.

<div [formGroup]="filterForm"> <!-- i think you missed this block -->
    <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

@irowbin
Copy link

irowbin commented Oct 2, 2018

@Rashid75 here is a working example of just to test the values:
https://stackblitz.com/edit/filter-columns?file=src%2Fapp%2Ffilter%2Ffilter-col.component.html
Click on the button to open matManu, change some values and then click to the filter. You'll see the form data. Sorry for the ugly code. 😄

@samuelkavin
Copy link

samuelkavin commented Oct 26, 2018

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
*Second filter with material chip needs to be work same as filter 1
*Text turn to chip when press enter

@c0d3r1010
Copy link

@samuelkavin That stackblitz link is 404 not found.

@Mkahnke
Copy link

Mkahnke commented Nov 7, 2018

@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.

@sandgupta23
Copy link

@samuelkavin can you post link again. Your stackblitz link isnt working.

@malbarmavi
Copy link

malbarmavi commented Feb 22, 2019

I have answered about this topic and create a repo explain how I did it Filtering different columns in a material table

image

source 🛠,live preview 🚀

@sbazinet
Copy link

I am trying to get this example to work with the code provided. However I'm getting an angular error on this line...

listings
error

Is this a problem because the control is in a submenu? If so can I go about fixing this?

@AxiomeCG
Copy link

AxiomeCG commented Jul 4, 2019

angular_table_filtered
Here is a link to the link to the stackblitz I used to develop my solution that you can browse in depth :
Angular Material Filtered Table

Explanation on the thinking process:

I developped a solution for this problem using Mat Menu and Dynamic component injection.
You will need a library named ng-dynamic-component to handle the inputs and the outputs of filters injected dynamically.

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 ColumnPredicate containing the name of the column to filter, and the predicate used to filter.

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.
It's a bit hacky for filtering, due to the unflexible behaviour of the table. I trigger the filter by passing a value that is not used in the filterPredicate logic.

  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:
Trigger Mat Menu => Inject dynamically a filter component and giving it the name of the column => The filter returns a ColumnPredicate based on the information filled up => dataSource.filterPredicate is updated with the predicate and a fake value is sent to trigger the filter => Filtering is done

I would love to have a method on dataSource with the signature addFilter(column: string, predicate: (columnValue: string) => boolean) that would be for me the most natural way to define a column filter and avoid my hacky part.

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.

@andzejsw
Copy link

Improved @alexisdoualle by allowing unlimited count of provided object keys and values and no need to know them by names: createFilter() { let filterFunction = function(data, filter) : boolean { let searchTerms = JSON.parse(filter); for (var property in searchTerms) { if (searchTerms.hasOwnProperty(property)) { if(data[property].toString().indexOf(searchTerms[property]) == -1) return false; } } return true; } return filterFunction; }

@Rajesh5496
Copy link

Rajesh5496 commented Apr 7, 2020

@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
at MatTableDataSource._this.filterPredicate

in Function at line this.dataSource.filter = searchFilter;
applyFilter() {
let searchFilter: any = {
values: this.searchValue,
conditions: this.searchCondition,
methods: this._filterMethods
}
console.log(this.dataSource);
this.dataSource.filter = searchFilter;
}

Can you plz plz help me

@irowbin
Copy link

irowbin commented Apr 11, 2020

@Rajesh5496

// the datasource filter expect string instead of object here. 
this.dataSource.filter = searchFilter;

// change as 
this.dataSource.filter =  'term'; 

check this doc

@andrewseguin
Copy link
Contributor

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 connect stream. If you are using the MatTableDataSource to do this, you may find it challenging since that data source is meant more for a quick solution to avoid implementing your own data source, and it is not meant for complex situations like multi-input filters.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jun 26, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: material/table docs This issue is related to documentation P4 A relatively minor issue that is not relevant to core functions
Projects
No open projects
Table
  
Docs
Development

No branches or pull requests