@smallpearl/ngx-helper 0.32.9 → 0.32.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/i18n/sp-mat-select-entity/en.json +1 -1
- package/assets/i18n/sp-mat-select-entity/zh-hant.json +1 -1
- package/entities/index.d.ts +2 -0
- package/entities/src/paged-loader.d.ts +212 -0
- package/entities/src/paginator.d.ts +87 -0
- package/fesm2022/smallpearl-ngx-helper-entities.mjs +545 -0
- package/fesm2022/smallpearl-ngx-helper-entities.mjs.map +1 -0
- package/fesm2022/smallpearl-ngx-helper-mat-entity-list.mjs.map +1 -1
- package/fesm2022/smallpearl-ngx-helper-mat-select-entity.mjs +476 -471
- package/fesm2022/smallpearl-ngx-helper-mat-select-entity.mjs.map +1 -1
- package/fesm2022/smallpearl-ngx-helper-mat-select-infinite-scroll.mjs +138 -0
- package/fesm2022/smallpearl-ngx-helper-mat-select-infinite-scroll.mjs.map +1 -0
- package/mat-entity-list/src/mat-entity-list-types.d.ts +62 -0
- package/mat-select-entity/src/mat-select-entity.component.d.ts +71 -104
- package/mat-select-infinite-scroll/index.d.ts +2 -0
- package/mat-select-infinite-scroll/src/mat-select-infinite-scroll.directive.d.ts +19 -0
- package/mat-select-infinite-scroll/src/mat-select-infinite-scroll.service.d.ts +25 -0
- package/package.json +20 -11
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { HttpClient, HttpContext, HttpContextToken, HttpParams } from '@angular/common/http';
|
|
2
|
+
import { SPMatEntityListPaginator } from '@smallpearl/ngx-helper/mat-entity-list';
|
|
3
|
+
import { Observable, Subject, Subscription } from 'rxjs';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* A type representing an entity loader function that takes page number,
|
|
7
|
+
* page size, and an optional search value and returns an Observable of
|
|
8
|
+
* the response. This is similar the http.get() method of HttpClient but
|
|
9
|
+
* with pagination parameters. The return value is deliberately kept generic
|
|
10
|
+
* (Observable<any>) to allow flexibility in the response type. This reponse
|
|
11
|
+
* will be parsed by the provided paginator's parseRequestResponse() method.
|
|
12
|
+
* So as long as the function return type and paginator are compatible,
|
|
13
|
+
* any response type can be handled.
|
|
14
|
+
*
|
|
15
|
+
* Ideally the response should contain the total number of entities available
|
|
16
|
+
* at the remote and the array of entities for the requested page.
|
|
17
|
+
*/
|
|
18
|
+
export type SPEntityLoaderFn = (page: number, pageSize: number, searchValue: string | undefined) => Observable<any>;
|
|
19
|
+
/**
|
|
20
|
+
* Represents a request to load entities from the remote. This is used to
|
|
21
|
+
* compare two requests to determine if they are equal. This is useful to
|
|
22
|
+
* prevent duplicate requests being sent to the remote.
|
|
23
|
+
*/
|
|
24
|
+
declare class LoadRequest {
|
|
25
|
+
endpoint: string | SPEntityLoaderFn;
|
|
26
|
+
pageNumber: number;
|
|
27
|
+
searchStr: string | undefined;
|
|
28
|
+
force: boolean;
|
|
29
|
+
constructor(endpoint: string | SPEntityLoaderFn, pageNumber: number, searchStr: string | undefined, force?: boolean);
|
|
30
|
+
isEqualToAndNotForced(prev: LoadRequest): boolean;
|
|
31
|
+
}
|
|
32
|
+
type StateProps = {
|
|
33
|
+
allEntitiesLoaded: boolean;
|
|
34
|
+
loading: boolean;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* An abstract class that you can use wherever you would like to load entities
|
|
38
|
+
* from a remote endpoint in a paged manner. Entities can be loaded in one of
|
|
39
|
+
* two ways:
|
|
40
|
+
*
|
|
41
|
+
* 1. By providing an entityLoaderFn that takes an endpoint and HttpParams
|
|
42
|
+
* and returns a Observable of entities.
|
|
43
|
+
* 2. Or by providing a URL and using the default loader that uses HttpClient
|
|
44
|
+
* to load entities.
|
|
45
|
+
* This class uses RxJS to manage the loading of entities and provides
|
|
46
|
+
* signals to track the loading state, entity count, page index, page size,
|
|
47
|
+
* and whether more entities are available to load.
|
|
48
|
+
*
|
|
49
|
+
* How to use this class:
|
|
50
|
+
*
|
|
51
|
+
* 1. Dervice your component from SPPagedEntityLoader.
|
|
52
|
+
* 2. After your component is initialized, call the startLoader() method to
|
|
53
|
+
* get the component going. This sets up the necessary subscriptions to
|
|
54
|
+
* listen for load requests. Load requests are triggered by calling the
|
|
55
|
+
* loadPage() or loadNextPage() methods.
|
|
56
|
+
* 3. If your component supports infinite scrolling, call loadMoreEntities()
|
|
57
|
+
* method to load the next page of entities when it detects a scroll event.
|
|
58
|
+
* 4. If you component needs to load a specific page (via a pagination control),
|
|
59
|
+
* call the loadPage(pageNumber) method to load the specified page.
|
|
60
|
+
* 5. Entities are stored in an internal entities store which is an @ngneat/elf
|
|
61
|
+
* store. You can subscribe to the store's query to get the list of entities.
|
|
62
|
+
* 6. When your component is destroyed, call the stopLoader() method to clean up
|
|
63
|
+
* internal subscriptions.
|
|
64
|
+
*
|
|
65
|
+
* The class is decorated with Angular's @Directive decorator so that we can
|
|
66
|
+
* use signals for the input properties and dependency injection for HttpClient.
|
|
67
|
+
* There are no abstract methods as such, but the class is meant to be extended
|
|
68
|
+
* by your component to provide the necessary configuration via input properties.
|
|
69
|
+
* This is why it is declared as abstract.
|
|
70
|
+
*/
|
|
71
|
+
export declare abstract class SPPagedEntityLoader<TEntity extends {
|
|
72
|
+
[P in IdKey]: PropertyKey;
|
|
73
|
+
}, IdKey extends string = 'id'> {
|
|
74
|
+
static _entitiesCache: Map<string, {
|
|
75
|
+
refCount: number;
|
|
76
|
+
resp: any;
|
|
77
|
+
}>;
|
|
78
|
+
cacheKeys: Set<string>;
|
|
79
|
+
searchParamValue: string | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* Entity name, that is used to form the "New { item }" menu item if
|
|
82
|
+
* inlineNew=true. This is also used as the key of the object in GET response
|
|
83
|
+
* if the reponse JSON is an object (sideloaded response), where the values
|
|
84
|
+
* are stored indexed by the server model name. For eg:-
|
|
85
|
+
*
|
|
86
|
+
* {
|
|
87
|
+
* 'customers': [
|
|
88
|
+
* {...},
|
|
89
|
+
* {...},
|
|
90
|
+
* {...},
|
|
91
|
+
* ]
|
|
92
|
+
* }
|
|
93
|
+
*/
|
|
94
|
+
entityName: import("@angular/core").InputSignal<string>;
|
|
95
|
+
url: import("@angular/core").InputSignal<string | SPEntityLoaderFn>;
|
|
96
|
+
pageSize: import("@angular/core").InputSignal<number>;
|
|
97
|
+
paginator: import("@angular/core").InputSignal<SPMatEntityListPaginator | undefined>;
|
|
98
|
+
searchParamName: import("@angular/core").InputSignal<string>;
|
|
99
|
+
idKey: import("@angular/core").InputSignal<string>;
|
|
100
|
+
pluralEntityName: import("@angular/core").InputSignal<string | undefined>;
|
|
101
|
+
httpReqContext: import("@angular/core").InputSignal<[HttpContextToken<any>, any] | [[HttpContextToken<any>, any]] | undefined>;
|
|
102
|
+
httpParams: import("@angular/core").InputSignal<HttpParams | undefined>;
|
|
103
|
+
protected loadRequest$: Subject<LoadRequest>;
|
|
104
|
+
protected sub$: Subscription | undefined;
|
|
105
|
+
protected _pageSize: import("@angular/core").Signal<number>;
|
|
106
|
+
protected _pluralEntityName: import("@angular/core").Signal<string>;
|
|
107
|
+
protected _capitalizedEntityName: import("@angular/core").Signal<string>;
|
|
108
|
+
protected _httpReqContext: import("@angular/core").Signal<HttpContext>;
|
|
109
|
+
entityListConfig: import("@smallpearl/ngx-helper/mat-entity-list").SPMatEntityListConfig | null;
|
|
110
|
+
protected _paginator: import("@angular/core").Signal<SPMatEntityListPaginator>;
|
|
111
|
+
protected store: import("@ngneat/elf").Store<{
|
|
112
|
+
name: string;
|
|
113
|
+
state: {
|
|
114
|
+
entities: Record<TEntity[IdKey], TEntity>;
|
|
115
|
+
ids: TEntity[IdKey][];
|
|
116
|
+
} & StateProps & import("@ngneat/elf-pagination").PaginationState<0>;
|
|
117
|
+
config: never;
|
|
118
|
+
}, {
|
|
119
|
+
entities: Record<TEntity[IdKey], TEntity>;
|
|
120
|
+
ids: TEntity[IdKey][];
|
|
121
|
+
} & StateProps & import("@ngneat/elf-pagination").PaginationState<0>>;
|
|
122
|
+
protected http: HttpClient;
|
|
123
|
+
constructor();
|
|
124
|
+
/**
|
|
125
|
+
* Starts listening for load requests and processes them. Call this from your
|
|
126
|
+
* component's ngOnInit() or ngAfterViewInit() method.
|
|
127
|
+
*/
|
|
128
|
+
startLoader(): void;
|
|
129
|
+
/**
|
|
130
|
+
* Stops listening for load requests and cleans up subscriptions.
|
|
131
|
+
*/
|
|
132
|
+
stopLoader(): void;
|
|
133
|
+
/**
|
|
134
|
+
* Returns a boolean indicating whether all entities at the remote have been
|
|
135
|
+
* loaded. All entities are considered loaded when there are no more entities
|
|
136
|
+
* to load from the remote (that is all pages have been loaded without
|
|
137
|
+
* a search filter).
|
|
138
|
+
* @returns
|
|
139
|
+
*/
|
|
140
|
+
allEntitiesLoaded(): boolean;
|
|
141
|
+
/**
|
|
142
|
+
* Returns the total number of entities at the remote as reported by the
|
|
143
|
+
* server (or load fn) during each load.
|
|
144
|
+
* @returns
|
|
145
|
+
*/
|
|
146
|
+
totalEntitiesAtRemote(): number;
|
|
147
|
+
/**
|
|
148
|
+
* Returns number of entities currently stored in the internal store.
|
|
149
|
+
* @returns
|
|
150
|
+
*/
|
|
151
|
+
totalEntitiesCount(): number;
|
|
152
|
+
/**
|
|
153
|
+
* Returns true if there are more entities to load from the remote.
|
|
154
|
+
* This is computed based on the total entities count and the number of
|
|
155
|
+
* entities loaded so far. For this method to work correctly, an initial
|
|
156
|
+
* load must have been performed to get the total count from the remote.
|
|
157
|
+
* @returns
|
|
158
|
+
*/
|
|
159
|
+
hasMore(): boolean;
|
|
160
|
+
/**
|
|
161
|
+
* Returns true if a load operation is in progress. The load async operation
|
|
162
|
+
* method turns the loading state to true when a load operation starts and
|
|
163
|
+
* turns it to false when the operation completes.
|
|
164
|
+
* @returns
|
|
165
|
+
*/
|
|
166
|
+
loading(): boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Returns the endpoint URL if the loader was created with an endpoint.
|
|
169
|
+
* If the loader was created with a loader function, an empty string is
|
|
170
|
+
* returned.
|
|
171
|
+
* @returns
|
|
172
|
+
*/
|
|
173
|
+
endpoint(): string;
|
|
174
|
+
/**
|
|
175
|
+
* Loads the specified page number of entities from the remote.
|
|
176
|
+
* @param pageNumber
|
|
177
|
+
*/
|
|
178
|
+
loadPage(pageNumber: number): void;
|
|
179
|
+
/**
|
|
180
|
+
* Returns the next page number to be loaded. This is based on the current
|
|
181
|
+
* page number stored in the internal pagination state. Note that this method
|
|
182
|
+
* only makes sense when pages are loaded sequentially as in an infinite
|
|
183
|
+
* scroll UI.
|
|
184
|
+
* @returns
|
|
185
|
+
*/
|
|
186
|
+
nextPageNumber(): number;
|
|
187
|
+
/**
|
|
188
|
+
* Returns the total number of pages available at the remote.
|
|
189
|
+
* @returns
|
|
190
|
+
*/
|
|
191
|
+
totalPages(): number;
|
|
192
|
+
/**
|
|
193
|
+
* Loads the next page of entities from the remote. If forceRefresh is true,
|
|
194
|
+
* the internal store is reset before loading the next page. Use this for
|
|
195
|
+
* infinite scroll scenarios where you want to load the pages sequentially.
|
|
196
|
+
* @param forceRefresh
|
|
197
|
+
*/
|
|
198
|
+
loadNextPage(forceRefresh?: boolean): void;
|
|
199
|
+
setSearchParamValue(searchStr: string): void;
|
|
200
|
+
setEntities(entities: TEntity[]): void;
|
|
201
|
+
getEntities(): TEntity[];
|
|
202
|
+
getEntity(id: TEntity[IdKey]): TEntity | undefined;
|
|
203
|
+
protected doActualLoad(lr: LoadRequest): Observable<any>;
|
|
204
|
+
private existsInCache;
|
|
205
|
+
private getCacheKey;
|
|
206
|
+
private getFromCache;
|
|
207
|
+
addToCache(cacheKey: string, resp: any): void;
|
|
208
|
+
private removeFromCache;
|
|
209
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SPPagedEntityLoader<any, any>, never>;
|
|
210
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<SPPagedEntityLoader<any, any>, "**spPagedEntityLoader**", never, { "entityName": { "alias": "entityName"; "required": true; "isSignal": true; }; "url": { "alias": "url"; "required": true; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "paginator": { "alias": "paginator"; "required": false; "isSignal": true; }; "searchParamName": { "alias": "searchParamName"; "required": false; "isSignal": true; }; "idKey": { "alias": "idKey"; "required": false; "isSignal": true; }; "pluralEntityName": { "alias": "pluralEntityName"; "required": false; "isSignal": true; }; "httpReqContext": { "alias": "httpReqContext"; "required": false; "isSignal": true; }; "httpParams": { "alias": "httpParams"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
211
|
+
}
|
|
212
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pagination HTTP request params. Actually copied from Angular's HttpParams
|
|
3
|
+
* declaration. The ReadonlyArray<string|number|boolean> is a bit of an
|
|
4
|
+
* overkill for pagination params, but what the heck. When you copy-paste,
|
|
5
|
+
* do it in full!
|
|
6
|
+
*/
|
|
7
|
+
export type SPPageParams = {
|
|
8
|
+
[param: string]: string | number | boolean | ReadonlyArray<string | number | boolean>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* An interface that the clients should provide, either via a global config
|
|
12
|
+
* (see above), that handles parsing the GET response and returns the entities
|
|
13
|
+
* stored therein. This class will allow the entity-list component to be
|
|
14
|
+
* used across different pagination response types as long as the appropriate
|
|
15
|
+
* SPEntityListPaginator class is provided to the component.
|
|
16
|
+
*/
|
|
17
|
+
export interface SPEntityListPaginator {
|
|
18
|
+
/**
|
|
19
|
+
* Return the HTTP request params for the given page index and page size as
|
|
20
|
+
* an object. For example, for a REST API that supports 'skip' and 'top' params,
|
|
21
|
+
* the implementation would be:
|
|
22
|
+
*
|
|
23
|
+
* ```typescript
|
|
24
|
+
* getRequestPageParams(endpoint: string, pageIndex: number, pageSize: number): SPPageParams {
|
|
25
|
+
* return {
|
|
26
|
+
* skip: pageIndex * pageSize,
|
|
27
|
+
* top: pageSize
|
|
28
|
+
* };
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
* @param endpoint
|
|
32
|
+
* @param pageIndex
|
|
33
|
+
* @param pageSize
|
|
34
|
+
* @returns
|
|
35
|
+
*/
|
|
36
|
+
getRequestPageParams: (endpoint: string, pageIndex: number, pageSize: number) => SPPageParams;
|
|
37
|
+
/**
|
|
38
|
+
* Parse the HTTP response received from the GET request and return an object
|
|
39
|
+
* containing the total number of entities available and the array of entities
|
|
40
|
+
* for the current page. For example, for the pure DRF paginated response
|
|
41
|
+
* like below:
|
|
42
|
+
* ```json
|
|
43
|
+
* {
|
|
44
|
+
* "count": 102,
|
|
45
|
+
* "next": "http://api.example.org/entities/?page=3",
|
|
46
|
+
* "previous": "http://api.example.org/entities/?page=1",
|
|
47
|
+
* "results": [
|
|
48
|
+
* {
|
|
49
|
+
* "id": 1,
|
|
50
|
+
* "name": "Entity 1"
|
|
51
|
+
* },
|
|
52
|
+
* {
|
|
53
|
+
* "id": 2,
|
|
54
|
+
* "name": "Entity 2"
|
|
55
|
+
* }
|
|
56
|
+
* ]
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
* The implementation would be:
|
|
60
|
+
* ```typescript
|
|
61
|
+
* parseRequestResponse<TEntity extends { [P in IdKey]: PropertyKey }, IdKey extends string = 'id'>(
|
|
62
|
+
* entityName: string,
|
|
63
|
+
* entityNamePlural: string,
|
|
64
|
+
* endpoint: string,
|
|
65
|
+
* params: SPPageParams,
|
|
66
|
+
* resp: any
|
|
67
|
+
* ): { total: number; entities: TEntity[] } {
|
|
68
|
+
* return {
|
|
69
|
+
* total: resp.count,
|
|
70
|
+
* entities: resp.results
|
|
71
|
+
* };
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
* @param entityName
|
|
75
|
+
* @param entityNamePlural
|
|
76
|
+
* @param endpoint
|
|
77
|
+
* @param params
|
|
78
|
+
* @param resp
|
|
79
|
+
* @returns
|
|
80
|
+
*/
|
|
81
|
+
parseRequestResponse: <TEntity extends {
|
|
82
|
+
[P in IdKey]: PropertyKey;
|
|
83
|
+
}, IdKey extends string = 'id'>(entityName: string, entityNamePlural: string, endpoint: string, params: SPPageParams, resp: any) => {
|
|
84
|
+
total: number;
|
|
85
|
+
entities: TEntity[];
|
|
86
|
+
};
|
|
87
|
+
}
|