Gathering detailed insights and metrics for ngx-collection
Gathering detailed insights and metrics for ngx-collection
Gathering detailed insights and metrics for ngx-collection
Gathering detailed insights and metrics for ngx-collection
npm install ngx-collection
Typescript
Module System
Node Version
NPM Version
71.8
Supply Chain
96.7
Quality
82.7
Maintenance
100
Vulnerability
99.3
License
TypeScript (100%)
Love this project? Help keep it running — sponsor us today! 🚀
Total Downloads
14,630
Last Day
2
Last Week
70
Last Month
445
Last Year
3,861
MIT License
32 Stars
114 Commits
2 Forks
2 Watchers
1 Branches
1 Contributors
Updated on Feb 11, 2025
Minified
Minified + Gzipped
Latest Version
4.3.2
Package Id
ngx-collection@4.3.2
Unpacked Size
439.74 kB
Size
82.92 kB
File Count
23
NPM Version
10.9.0
Node Version
22.9.0
Published on
Dec 01, 2024
Cumulative downloads
Total Downloads
Last Day
0%
2
Compared to previous day
Last Week
-28.6%
70
Compared to previous week
Last Month
115%
445
Compared to previous month
Last Year
-44.6%
3,861
Compared to previous year
1
2
Collection State Management Service
By using this service, you can easily and safely modify collections of items and monitor their state (as well as the state of their modifications).
All the actions are immutable - items will not be modified.
Collection method calls can be completely synchronous, or asynchronous (preventing data race in asynchronous calls).
Out of the box, without any additional code, you'll be able to control your "loading" spinners, temporarily disable buttons, display success/error messages, and much more.
You can read an introductory article that includes an example of building this application.
Here you can see how little code you need to gently manipulate your collection of art!
✅ No data race in asynchronous calls:
async
pipe and subscribe()
, or with some store;✅ The service is not opinionated:
switchMap()
, mergeMap()
, concatMap()
, forkJoin()
, or something else;of()
or signal()
for this purpose).✅ Safety guarantees:
Requires Angular 17+.
Should work fine with Angular 16 (Angular 17 is required for tests in this repository).
Yarn:
yarn add ngx-collection
NPM:
npm i ngx-collection
In your code:
1import { Collection } from 'ngx-collection';
The API has a lot of fields and methods, but you don't have to learn and use all of them.
Just use the fields and methods that your application needs.
No worries, in your app you'll use just a few methods and even fewer fields.
API has all these methods and fields to be flexible for many different types of usage.
You can use Collection
class as is, or you can use it inside an @Injectable
class, or you can create an @Injectable
class, extending Collection
class.
With @Injectable
, you can control how the instance will be shared across the components.
The Collection Service has four main methods to mutate a collection: create()
, read()
, update()
, delete()
.
Call create
to add a new item to a collection:
1this.booksCollection.create({ 2 request: this.booksService.saveBook(bookData), 3 onSuccess: () => this.messageService.success('Created'), 4 onError: () => this.messageService.error('Error'), 5})
read()
will load the list of items:
1this.booksCollection.read({ 2 request: this.booksService.getBooks(), 3 onError: () => this.messageService.error('Can not load the list of books') 4 })
Use update()
to modify some particular item in your collection:
1this.booksCollection.update({ 2 request: this.booksService.saveBook(bookData), 3 item: bookItem, 4 onSuccess: () => this.messageService.success('Saved'), 5 onError: () => this.messageService.error('Error'), 6})
The usage of delete()
is obvious. Let's explore a more detailed example:
1export class BookStore extends ComponentStore<BookStoreState> { 2 3 public readonly remove = this.effect<Book>(_ => _.pipe( 4 exhaustMap((book) => { 5 if (!book) { 6 return EMPTY; 7 } 8 return openModalConfirm({ 9 title: 'Book Removal', 10 question: 'Do you want to delete this book?', 11 }).afterClosed().pipe( 12 exhaustMap((result) => { 13 if (result) { 14 return this.booksCollection.delete({ 15 request: book.uuId ? this.booksService.removeBook(book.uuId) : undefined, 16 item: book, 17 onSuccess: () => this.messageService.success('Removed'), 18 onError: () => this.messageService.error('Error'), 19 }); 20 } 21 return EMPTY; 22 }) 23 ); 24 }) 25 )); 26}
1@Component({
2 selector: 'example',
3 standalone: true,
4 ///...
5})
6export class ExampleComponent {
7 // this collection will be only accessible to this component
8 protected readonly collection = new ExampleCollection({comparatorFields: ['id']});
9}
1@Injectable()
2export class ExampleCollection extends Collection<Example> {
3 constructor() {
4 super({comparatorFields: ['id']});
5 }
6}
7
8@Component({
9 selector: 'example',
10 // ...
11 providers: [
12 ExampleCollection, // 👈 You need to declare it as a provider
13 // in the "container" component of the "feature"
14 // or in the Route object, that declares a route to the "feature".
15 // Other components (of the "feature") will inherit it from the parent components.
16 ]
17})
18export class ExampleComponent {
19 protected readonly coll = inject(ExampleCollection);
20}
If you want to access some collection from any component, you can create a global collection.
One example use case is having a list of items (ListComponent), and every item is rendered using a component (ListItemComponent). If both ListComponent and ListItemComponent use the same shared collection, changes made to one of them will be instantly reflected in the other.
To create a global collection, create a new class that extends this service and add the @Injectable({providedIn: 'root'})
decorator:
1@Injectable({ providedIn: 'root' }) 2export class BooksCollection extends Collection<Book> { 3 constructor() { 4 super({comparatorFields: ['id']}); 5 } 6}
1@Component({ 2 selector: 'book', 3 standalone: true, 4 ///... 5 providers: [ 6 //... 7 // BooksCollection should not be added here ⚠️ 8 ], 9}) 10export class BookComponent { 11 protected readonly books = inject(BooksCollection); 12}
1export class BookStore extends ComponentStore<BookStoreState> { 2 public readonly coll = inject(BooksCollection); 3}
You can set statuses for the items. Statuses can be unique per collection (for example: 'focused') or not (for example: 'selected'). Statuses are not predefined; you can use your list of statuses. The service only needs to know if a given status is unique or not unique.
The equality of items will be checked using the comparator, which you can replace using the setComparator()
method.
The comparator will first compare items using ===
, then it will use id fields.
You can check the default id fields list of the default comparator in the comparator.ts file.
You can easily configure it using constructor()
, setOptions()
, or by re-instantiating a Comparator, or by providing your own Comparator - it can be a class, implementing ObjectsComparator
interface, or a function, implementing ObjectsComparatorFn
.
1export class NotificationsCollection extends Collection<Notification> { 2 constructor() { 3 super({ comparatorFields: ['id'] }); 4 } 5 6 override init() { 7 // or 8 this.setOptions({ comparatorFields: ['uuId', 'url'] }); 9 10 // or: 11 this.setComparator(new Comparator(['signature'])); 12 13 // or: 14 this.setComparator((a, b) => a.id === b.id); 15 } 16}
In the default comparator, each item in the list of fields can be:
string
- if both objects have this field, and values are equal, the objects are considered equal.string[]
- composite field: If both objects have every field listed, and every value is equal, the objects are considered equal.Every field in the list will be treated as path, if it has a dot in it - this way you can compare nested fields.
The Collection Service will not allow duplicates in the collection.
Items will be checked before adding to the collection in the create()
, read()
, update()
, and refresh()
methods.
To find a duplicate, items will be compared by using the comparator. Object equality check is a vital part of this service, and duplicates will break this functionality.
A collection might have duplicates due to some data error or because of incorrect fields in the comparator. You can redefine them to fix this issue.
If a duplicate is detected, the item will not be added to the collection, and an error will be sent to the errReporter
(if errReporter
is set).
You can call setThrowOnDuplicates('some message')
to make the Collection Service throw an exception with the message you expect.
The read()
method, by default, will put returned items to the collection even if they have duplicates, but the errReporter
will be called (if errReporter
is set) because in this case, you have a chance to damage your data in future update()
operations.
You can call setAllowFetchedDuplicates(false)
to instruct read()
not to accept items lists with duplicates.
In every params object, request
is an observable or a signal that you are using to send the request to the API.
Only the first emitted value will be used.
If the request is a signal, the signal will be read once at the moment of request execution.
The same rule applies to arrays of observables and signals, as some methods accept them too.
1 return this.exampleCollection.update({ 2 request: this.exampleService.saveExample(data), 3 item: exampleItem, 4 onSuccess: () => this.messageService.success('Saved'), 5 onError: () => this.messageService.error('Error'), 6 });
The item
parameter is the item that you are mutating.
You receive this item from the items field of the collection state.
1 remove = createEffect<Example>(_ => _.pipe( 2 exhaustMap((example) => { 3 return this.examplesCollection.delete({ 4 request: example.uuId ? this.exampleService.removeExample(example.uuId) : signal(null), 5 item: example, 6 onSuccess: () => this.messageService.success('Removed'), 7 onError: () => this.messageService.error('Error'), 8 }); 9 }) 10 ));
You can send just a part of the item object, but this part should contain at least one of the comparator's fields (id fields).
See "Items comparison" for details.
1 remove = createEffect<string>(_ => _.pipe( 2 exhaustMap((uuId) => { 3 return this.examplesCollection.delete({ 4 request: uuId ? this.exampleService.removeExample(uuId) : signal(null), 5 item: {uuId: uuId}, 6 onSuccess: () => this.messageService.success('Removed'), 7 onError: () => this.messageService.error('Error'), 8 }); 9 }) 10 ));
FetchedItems<T>
The read()
method additionally supports a specific type from the request execution result, not just a list of items but a wrapper containing a list of items: FetchedItems
type.
You can (optionally) use this or a similar structure to don't lose meta information, such as the total count of items (usually needed for pagination).
Copy of ComponentStore.effect()
method from NgRx, where takeUntil(this.destroy$)
is replaced with takeUntilDestroyed(destroyRef)
, to use it as a function.
createEffect()
is not a method of Collection
class, it's a standalone function.
You can find documentation and usage examples here: https://ngrx.io/guide/component-store/effect#effect-method
Checks if some item belongs to some array of items - a comparator of this collection will be used.
item
array
Example of usage:
1<mat-chip-option 2 *ngFor="let role of $allRoles()" 3 [value]="role" 4 [selected]="coll.hasItemIn(role, $roles())" 5 [selectable]="false" 6> 7 <span>{{role.name}}</span> 8</mat-chip-option>
For your convenience, there is a protected init()
method that you can override if you want some special initialization logic, so you don't have to deal with overriding the constructor()
method.
Original method is guaranteed to be empty, so you don't have to call super.init()
.
Will be called from the constructor()
.
Another method you can safely override.
Original method is guaranteed to be empty, so you don't have to call super.asyncInit()
.
Will be called in the next microtask from the constructor (init()
will be called first and in the current microtask).
No vulnerabilities found.
No security vulnerabilities found.
ngx-color
A Collection of Color Pickers from Sketch, Photoshop, Chrome & more
ngx-simple-widgets
**Simple Widgets** is an [**Angular**](https://angular.io) component library that offers a collection of components designed to maintain a harmonious and unified user experience. These components are meticulously crafted with a consistent theme, drawing i
ngx-widgets
A collection of Angular components and other useful things to be shared.
ngx-order-pipe
Angular order pipe, order collection by a field