7.0.2 • Published 3 months ago

akita-filters-mat-datasource v7.0.2

Weekly downloads
-
License
Apache License 2....
Repository
github
Last release
3 months ago

Akita Filters Plugins Mat Data Source

npm npm bundle size GitHub last commit NPM License NPM Version NPM Version

Sometimes, you need to display a list and provide users the ability to filter your list. Entity-store give the ability to filter, a sorting, by given options to selectAll() function. But each time, you want to change this filter, you need to recall the function.

Filters plugins give you the possibility to managed multiples filters, add, remove and update filters, and each time filters have been updated, new filtered value has been emitted.

Usage

This could be useful, to display :

  • products list, (with categories filter, search, price filter, etc...)
  • Store locator (with filter by region, location, etc...)
  • portfolio, image gallery
  • Any list of elements that need multiple filters
  • Config filter that could be applied in multiple pages
  • ...

Advantage :

  • Add multiple filters (dynamically add, remove and update filters) without changing data.

  • The filters and the entity query could be separated. You could have one component, that displays only your element. Is just make a select, to observe and display all information. And have another component to manage all filters.

  • You could also display a list of filters, and permit to delete one.

  • You could set the order to apply all filters

This specific package is only for Angular Material data table. But Akita filters plugins could be used without angular material. And maybe without angular. This was released since version 4.x as a sub package to avoid error, when not using Angular Material.

Install the new module akita-filters-mat-datasource

npm install --save akita-filters-mat-datasource

yarn add akita-filters-mat-datasource

or to install both package use this :

npm install --save akita-filters-plugin akita-filters-mat-datasource

yarn add akita-filters-plugin akita-filters-mat-datasource

Data Connector for Angular Material Table.

For dealing with angular material table, you need to provide a Data Connector. This connector, help you by just giving the Entity Store. Data Connector, will deal with Akita Filter for you.

Define your data source here :

    this.dataSource = new AkitaMatDataSource<EntityState>(EntityQuery);
    this.dataSource.setDefaultSort('colomnName', 'asc');

Import it with package :

import { AkitaMatDataSource } from 'akita-filters-mat-datasource';

Then use it in Mat Data Table like other data source.

<table
              mat-table
              #table
              [dataSource]="dataSource"
              [trackBy]="trackByName" 
              matSort
            >...</table>

Demo

A demo page is available in the playground "angular-material-demo" .

Dependencies

Need to have installed in your project these APIs : "@angular/material": "latest", "@angular/cdk": "latest"

Constructor, use existing AkitaFiltersPlugin

If needed you can specify, an already existing AkitaFiltersPlugins in the constructor. Useful to share it with another page/components. @see demo : angular-material-demo. Else, it will create an internal AkitaFiltersPlugins.

    this.dataSource = new AkitaMatDataSource<EntityState>(this.productsQuery, this.productsService.filtersProduct);

Function

Then you have some function that you can use to manage filters

filter/search properties : set search(search: string)

By setting search properties, you set a filter like search.

this.dataSource.search = "Search"; 

Both use filter and filter, but prefer using search, as filter is so confusing with setFilters functions. ("filter" is here to be the same as the MatDataSource) You can also customize the filter ID, if different in your server API

    this.dataSource = new AkitaMatDataSource<PhotosState>(this.photosQuery, this.photosService, {
    searchFilterId: 'search', // you can set the id of this filter, usefull if the params is different for you (default : "search")
});

Sort properties : set sort(sort: MatSort)

By setting Mat Sort for sorting you can set the sort. Used by Mat Table when changing filter

  @ViewChild(MatSort, { static: true }) sort: MatSort;

ngAfterViewInit(): void {
  this.dataSource.sort = this.sort;
}

Paginator properties : set paginator(paginator: MatPaginator)

By setting MatPaginator to enable pagination with datasource. Used by Mat Paginator to define pagination

@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
  
  ngAfterViewInit(): void {
    this.dataSource.paginator = this.paginator;
  }

And add the MatPaginator directly like this in the template. No need to give the size, as it will be settled by the data source.

    <mat-paginator #paginator
                   [pageIndex]="0"
                   [pageSize]="25"
                   [pageSizeOptions]="[10, 25, 50, 100, 250]">
    </mat-paginator>

Paginates server side : use server side pagination

By setting MatPaginator (cf before), it will use a local pagination. You can specify the option : "serverPagination" to use server side pagination. (Need also to set a MatPaginator). It will subscribe to MatPaginator change page, and create a server filter that send the page Number, and page size. We will be then notified in withServer callback function.

See example in "photos" page.

    this.dataSource = new AkitaMatDataSource<PhotosState>(this.photosQuery, this.photosService, {
    serverPagination: true, // set to true, to use server side pagination.
    pageIndexId: '_page', // you can set the id of this filter, usefull if the params is different for you (default : "page")
    pageIndexDisplay: true, // Set to true to display page filter (default: false)
    pageIndexName: 'Page', // Set the Name, to you filter, usefull if you want to display the filter : "Name: (value)" (default: "Page")
    pageSizeId: '_limit', // you can set the id of this filter, usefull if the params is different for you (default : "size")
    pageSizeDisplay: true, // Set to true to display size filter (default: false)
    pageSizeName: 'Size', // Set the Name, to you filter, usefull if you want to display the filter : "Name: (value)" (default: "Size")
    debounceTimeBetweenTwoChanges: 60, // Debounce time number between two changes, to avoid closest multiples changes events  
    resetPageIndexOnFiltersChange: true, // If true, will resets page Index after each filters changes (default: true)
});

You can also set options after constructor with function :

    this.dataSource = new AkitaMatDataSource<PhotosState>(this.photosQuery, this.photosService).withOptions({
  serverPagination: true, // set to true, to use server side pagination.    
});

But you will need to set the total by your one, depending on how you get this information.

    this.dataSource.total = 100; // set the total to Mat Paginator
console.log('total number', this.dataSource.total); // or get the setted total, was the length setted in Mat Paginator

Subscribe to filter changes

subscribe to be noticed when a filter has changed (and with server pagination, will exclude pagination filters).

    this.dataSource.onFiltersChanges$.subscribe(() => {
  // have some actions here 
});

AkitaFilters properties : get akitaFiltersPlugin(): AkitaFiltersPlugin

Access to the AkitaFilters plugins instance, and use all function from AkitaFilters plugins.

this.dataSource.akitaFiltersPlugin.setFilter({
                                     id: 'category',
                                     value: 'garden',
                                     predicate: (value: ProductPlant, index, array) => value.category === category
                                   }); 

setDefaultSort : public setDefaultSort(sortColumun: keyof T, direction: 'asc' | 'desc' = 'asc')

Set the default sort.

this.dataSource.setDefaultSort('colomnName', 'asc');

Proxy helper function

Some proxy function, just to call AkitaFilters Plugins.

    setFilter(filter: Partial<AkitaFilterBase< S >>): void; // Create or update a filter. Any mandatory properties, will be added
    setFilters(filter: Partial<AkitaFilterBase< S >>[]): void; // Create or update multiples filters in one time with emit changes onlu once
    removeFilter(id: ID): void; // Remove a filter by their name
    removeFilters(id: ID[]): void; // Remove multiples filters with emit changes onlu once
    clearFilters(): void; // Remove all filters 
    getFilterValue< S >(id: string): E | null; // Get a filters values 

Compatibility with MatTableDataSource functions

Compatibility has been added with all methods and properties present in MatDatasource. (except the method "sortData" because the sorting in Akita works differently). Which implements the MatTableDataSourceInterface which takes all the methods and properties of the following MatTableDataSource:

export interface MatTableDataSourceInterface<T> {
    data: T[];
    filter: string;
    paginator: MatPaginator;
    sort: MatSort;
    filterPredicate: ((data: T, filter: string) => boolean);
    filteredData: T[];
    // Not Implemented : sortData: ((data: T[], sort: MatSort) => T[]);
    sortingDataAccessor: ((data: T, sortHeaderId: string) => string | number);
}

Properties :

  • data : getter and setter for the data that will be managed in the datasource
  • filter: string, to perform a full text search in the data.
  • paginator: getter and setter to use pagination with MatPaginator
  • sort: getter and setter to use sorting with MatSort
  • filteredData : to retrieve synchronously the filtered data in the datasource

filterPredicate :

Is the function that is called by default, for filtering the data during the simple search. This method can be overridden to use a different function as it is the case for MatDataSource.

/**
* Checks if a data object matches the data source's filter string. By default, each data object
* is converted to a string of its properties and returns true if the filter has
* at least one occurrence in that string. By default, the filter string has its whitespace
* trimmed and the match is case-insensitive. May be overridden for a custom implementation of
* filter matching.
* @param data Data object used to check against the filter.
* @param filter Filter string that has been set on the data source.
* @returns Whether the filter matches against the data
  */
  filterPredicate: ((data: E, filter: string) => boolean) = (data: E, searchFilter: string) => {
  return defaultFilter(data, null, null, {value: searchFilter});
  }

sortData : / sortFunction

Throw an error, because this function cannot be used in akita sorting.

You can use instead "sortFunction" which will be the function used with Akita, to perform the comparison. The override method should have this signature : ((a: E, b: E, sort: MatSort) => 0 | 1 | -1) = (a, b, sort): 0 | 1 | -1

sortingDataAccessor

As in MatTableDataSource, you can define a custom sortingDataAccessor, that need to have this signature : ((data: T, sortHeaderId: string) => string | number)

/**
 * Data accessor function that is used for accessing data properties for sorting through
 * the default sortFunction.
 * This default function assumes that the sort header IDs (which defaults to the column name)
 * matches the data's properties (e.g. column Xyz represents data['Xyz']).
 * May be set to a custom function for different behavior.
 * @param data Data object that is being accessed.
 * @param sortHeaderId The name of the column that represents the data.
 */
sortingDataAccessor: ((data: T, sortHeaderId: string) => string | number) =
  (data: T, sortHeaderId: string): string|number => {
    const value = (data as {[key: string]: any})[sortHeaderId];

    if (_isNumberValue(value)) {
      const numberValue = Number(value);

      // Numbers beyond `MAX_SAFE_INTEGER` can't be compared reliably so we
      // leave them as strings. For more info: https://goo.gl/y5vbSg
      return numberValue < MAX_SAFE_INTEGER ? numberValue : value;
    }

    return value;
  }

WithServer : you can also use Akita-Mat-DataSource with server call

You can also use AkitaFilters plugins withServer in Akita-Mat-DataSource by using AkitaFilters Plugins function. Or there is also a function similar in Akita-Mat-DataSource.

Breaking Changes : 3.x to 4.x

Akita-mat-data-source is now a subpackage to avoid error with akita-filters-plugin, if you don't use Angular Material.

Changes this

import { AkitaMatDataSource } from 'akita-filters-plugin';

to

import { AkitaMatDataSource } from 'akita-filters-mat-datasource';

Breaking Changes : 2.x to 3.x

To correspond with Akita, you need now to specify only the entityState. The entity element is calculated as in akita with getEntityType

Changes this

new AkitaFiltersPlugin<MyEntitiesState, MyEntity>()

to

new AkitaFiltersPlugin<MyEntitiesState>()

Changes this

AkitaFilter<MyEntitiesState, MyEntity>[]

to

AkitaFilterBase<MyEntitiesState>[]

Changes this

new AkitaMatDataSource<MyEntity, MyEntitiesState>()

to

new AkitaMatDataSource<MyEntitiesState>()

Breaking Changes : 3.x to 4.x

Only update all libraries : Use last version of Angular, and last version of Akita

Breaking Changes : 4.x to 5.x

Deprecation of AkitaFilter type. Use AkitaFilterLocal when you use local filters, and AkitaFilterServer, when you use server feature. All type extends AkitaFilterBase, this type is used in the libraries. So you can also use it.

Breaking Changes : 5.x to 6.x

update to angular 10. So this libs should not be fully compatible with previous Angular version.

Breaking Changes : 6.x to 7.x

  • update to angular 17 and Build in Ivy modes.
  • Minimal version is Angular 16 and Angular Material 16
  • Akita filters Mat Datasource is no longer published in the same package o Akita-filter-plugins.
    • You need to install it from a separate package
    • Imports it from different package

Install the new module akita-filters-mat-datasource

npm install --save akita-filters-mat-datasource

yarn add akita-filters-mat-datasource

Import it with package :

import { AkitaMatDataSource } from 'akita-filters-mat-datasource';

npm page : https://www.npmjs.com/package/akita-filters-mat-datasource