angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.4k stars 6.76k forks source link

Relax MatTableDataSource’s filter to be of type “{}” #16112

Open paulferaud opened 5 years ago

paulferaud commented 5 years ago

Feature Description

Relax MatTableDataSource.filter to accept {}. Right now, it is restricted to string. This would allow much easier custom filtering on multiple dimensions.

Use Case

When the filter is “only” a string, it makes it very difficult to “structurally” filter a table on multiple dimensions, even when customizing filterPredicate . Some recommendations on internet include:

While it works, it’s also a gratuitous workaround: It turns out that at no point does MatTableDataSource actually require filter to be a string: Whatever gets passed to filter just gets piped “as-is” to filterPredicate.

Here is a simple fork of “Table with filtering” that filters on different columns individually, where all I did was pass my complex object, while not respecting : https://stackblitz.com/edit/table-filtering-multiple-filters-example?file=app/table-filtering-example.html https://table-filtering-multiple-filters-example.stackblitz.io/

Caveats

It would still be up to the caller to make sure that their filter object is homogeneous with their filterPredicate object.

paulferaud commented 4 years ago

Any chance we could prioritize this? It’s an absurdly simple change that would solve a problem that just keeps coming up and up and up:

salemdar commented 3 years ago

Any update on this issue?

angular-robot[bot] commented 2 years ago

Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.

Find more details about Angular's feature request process in our documentation.

angular-robot[bot] commented 2 years ago

Thank you for submitting your feature request! Looks like during the polling process it didn't collect a sufficient number of votes to move to the next stage.

We want to keep Angular rich and ergonomic and at the same time be mindful about its scope and learning journey. If you think your request could live outside Angular's scope, we'd encourage you to collaborate with the community on publishing it as an open source package.

You can find more details about the feature request process in our documentation.

ayhanyildiz commented 2 years ago

this is literally a bug. this doesn't need votes! when you have FormGroup, valueChanges are in object type. If you can't even handle your own feature, that is bug! please fix it already!

plastikaweb commented 1 month ago

I've done a workaround, and it works but years have passed and definitely, an option to pass some configuration besides a simple string to the filterPredicate should be already added to the MatTable API:

  1. I have a CustomTableComponent with these two Inputs:
@Input() data: T[] = [];

@Input() filterCriteria: Record<string, string>;

@Input() filterPredicate: (data: T, criteria: Record<string, string>) => boolean;
  1. And attach the fiterPredicate function like this to the dataSource.filterPredicate:
this.dataSource.filterPredicate = (data: T) =>
   this.filterPredicate ? this.filterPredicate(data as T, this.filterCriteria) : true;
}

this.dataSource.data = this.data;
  1. In my parent component where I'm using the CustomTableComponent I can define Inputs like this:

interface Item = { name: string, description: string, inStock: boolean}

@Component({
  ...
})
export class ParentComponent {
  data: Item[] = [];

  filterCriteria = signal<Record<string, string>>({
      text: '',
      inStock: '',
    });
    tableFilterPredicate = (data: Item, criteria: Record<string, string>) => {
      let filterText = true;
      let filterInStock = true;
      for (const key in criteria) {
        const value = criteria[key].toLowerCase();

        if (key === 'text') {
          filterText = [data.name, data.category.name].some(
            text => text?.toLowerCase().includes(value)
          );
        }

        if (key === 'inStock') {
          if (value === 'true') {
            filterInStock = data.inStock;
          } else if (value === 'false') {
            filterInStock = !data.inStock;
          } else {
            filterInStock = true;
          }
        }
      }

      return filterText && filterInStock;
    };

   // this could be attached two any filter form so the filterCriteria changes and the CustomTableComponent reacts to it:
   onChangeFilterCriteria(criteria: Record<string, string>): void {
      this.filterCriteria.update(() => criteria);
    }
}

and pass them to the CustomDataTable Component:

<custom-table
  [data]="tableData()"
  [filterCriteria]="filterCriteria() || {}"
  [filterPredicate]="tableFilterPredicate"
  ... any other configuration inputs
>
</custom-table>

Hope this helps!