Angular Library for working with lists. Includes filtering, sorting, updates and pagination. The ListService creates a Observable stream from a provided data array.
npm install @politie/ngx-list-service --save
To use the ListService, provide it to your @Component
decorator by adding the service into the providers array. This makes sure that a unique ListService instance is created for each component where you use the service.
Create a property called result$
, which is of type Observable<ListResult<T>>
and assign it in the constructor to the ListService result$
observable.
import { ListService, ListResult } from '@politie/ngx-list-service';
import { OnInit } from '@angular/core';
import { Observable } from 'rxjs';
@Component({
...,
providers: [
ListService
]
})
export class MyComponent implements OnInit {
public result$: Observable<ListResult<MyType>>;
constructor(private listService: ListService<MyType>) {
this.result$ = this.listService.result$;
}
ngOnInit() {
this.listService.create({
list: myData,
pageSize: 25
});
}
}
You can then call the create
method on the ListService class to create a list.
The create method takes your list configuration and data and returns the sorted and filtered list via the list$ observable.
Property | Type | Description | Default |
---|---|---|---|
list* | T[] or Observable<T[]> |
Array (or observable with array) of objects containing the data that should be displayed. | [] |
pageSize? | number |
How many items should be returned per page? Set to 0 for no pages. |
0 |
sort | {key: property: Extract<keyof T, string>, order: 'asc' / 'desc' } |
If you want to sort the list on initialzation, set the sort property to the key you want to sort the list to. | { key: null, order: 'asc' } |
filterFunction | (item: T) => boolean |
Define a custom filter function. See Filtering the List for a example. | null |
sortFunction | (item: T, property: Extract<keyof T, string>) => any) |
If you want to override the default sorting behaviour, you can do so by adding your own sortFunction. See Sorting the List for a example. | null |
Update the data list with a new set. This will return a new page of the data, based on the filtering and sorting options already set.
Sorts the list by the given key
. The sorting starts in ascending
order. If sort()
is called with the same key, the order is reversed.
If pagination is active and
sort()
is called, the pagination will be reset to the first page of results.
Filter the list by the given function. If you don't provide a function, the function provided in the config will be run (if provided).
If pagination is active and
filter()
is called, the pagination will be reset to the first page of results.
If pagination is active, grab the next page
of data and emit the result to the result$
observable.
If pagination is active, grab the previous page
of data and emit the result to the result$
observable.
If pagination is active, go to the provided page and emit the new result to the result$
observable.
There will be a check in place for checking if the page to go to is within the bounds of the list.
Sets the page size of the list to a new size.
If pagination is active and
setPageSize()
is called with a number higher than 0, the pagination will be reset to the first page of results.
The result$ observable will emit a new result whenever the ListService update()
, sort()
or filter()
methods are called. The result$
observable contains the current page of items, the active sorting options and properties to create pagination. The object that is returned from this observable looks like this:
{
page: `T[]`, // The current page (based on pagination and pageSize) of the filtered and sorted list
sorting: {
key: `Extract<keyof T, string>`,
order: 'asc|desc'
},
pagination: {
listSize: `number`, // Length of the filtered and sorted list
page: {
current: `number`, // The current page (1-based)
size: `number` // Number of items in this page
total: `number` // Total number of pages in the filtered and sorted list
},
pages: `number[]` // Array of page numbers (1-based) to create pages in the view
disabled: {
prev: `boolean`, // Should a prev button be disabled (current page is start of list)
next: `boolean` // Should a next button be disabled (current page is end of list)
}
}
}
With the information in the object, you can create tables
, lists
or anything that's suited for your data. With the pagination
object, you can create simple next/prev
buttons for navigating the list, but also more complex solutions with page numbers.
You can define your own filterFunction
to add your own filter logic. The function takes one parameter: the current item in the list. The function will run over every item in the provided data[]
array when create()
and/or filter()
is called. Let's say we have the following type defined for our array of objects:
type User {
id: number;
name: string;
lastActive: string;
}
And we have hooked up a FormControl
for searching for users by name (the searchInput
). We can then implement our filter logic like this:
import { OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
const myList: User[] = [
{
id: 1,
name: 'User',
lastActive: 1613407049
},
...
];
export class MyComponent implements OnInit {
searchInput = new FormControl('');
ngOnInit() {
this.listService.create({
list: myList,
pageSize: 25,
filterFunction: (item: User): boolean => {
// If we can't find the search string in the name, we should return false
if (!item.name.toLowerCase().includes(this.searchInput.value.toLowerCase())) {
return false;
}
// By default, we would like to display the item
return true;
}
});
}
}
You can also manually call the
filter()
with a function other than the function you provide in the configuration increate()
. If you add a function infilter()
, this function is now used whenever the lists filters (called when youupdate()
the list. If you don't provide a function when callingfilter()
, the function in the config is used (or skipped, if you didn't provide a function in the config as well).
Sorting is done on the filtered list. You can define your own function to specify sorting. By default, the sorting logic does a greather than
check. If you'd like to compare dates for example, you can write your own sorting logic. Define a custom sort function when you create a ListService instance:
import { OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
export class MyComponent implements OnInit {
searchInput = new FormControl('');
ngOnInit() {
this.listService.create({
list: myList,
pageSize: 25,
sortFunction: (item: User, key: string): any => {
// If the key to sort is 'lastActive', we should return a new Date to compare
if (key === 'lastActive') {
return new Date(item.lastActive);
}
// By default, just return the value of the key to the sorting function inside the Service.
return item[key];
}
});
}
}
Run npm run build:lib
to build the project. The build artifacts will be stored in the dist/
directory. You can then cd
into the dist
to push this library to the NPM registry.
Run npm run test:lib
to execute the unit tests with Jest.
Run npm run eslint
. If you'd like to autofix the problems, use npm run eslint:fix
.