ngx-mat-searchable-select 1.0.0 → 2.0.0

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.
Files changed (35) hide show
  1. package/README.md +19 -127
  2. package/package.json +12 -44
  3. package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.component.html +75 -75
  4. package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.mock.ts +43 -43
  5. package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-select-infinite-scroll.directive.ts +52 -52
  6. package/.editorconfig +0 -16
  7. package/.vscode/extensions.json +0 -4
  8. package/.vscode/launch.json +0 -20
  9. package/.vscode/tasks.json +0 -42
  10. package/LICENSE +0 -21
  11. package/angular.json +0 -151
  12. package/projects/demo/public/favicon.ico +0 -0
  13. package/projects/demo/src/app/app.config.ts +0 -9
  14. package/projects/demo/src/app/app.html +0 -118
  15. package/projects/demo/src/app/app.scss +0 -64
  16. package/projects/demo/src/app/app.ts +0 -167
  17. package/projects/demo/src/index.html +0 -16
  18. package/projects/demo/src/main.ts +0 -6
  19. package/projects/demo/src/styles.scss +0 -31
  20. package/projects/demo/tsconfig.app.json +0 -17
  21. package/projects/demo/tsconfig.spec.json +0 -15
  22. package/projects/ngx-mat-searchable-select/README.md +0 -262
  23. package/projects/ngx-mat-searchable-select/package.json +0 -12
  24. package/tsconfig.json +0 -39
  25. /package/{projects/ngx-mat-searchable-select/karma.conf.js → karma.conf.js} +0 -0
  26. /package/{projects/ngx-mat-searchable-select/ng-package.json → ng-package.json} +0 -0
  27. /package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.component.spec.ts +0 -0
  28. /package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.component.ts +0 -0
  29. /package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.model.ts +0 -0
  30. /package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.service.spec.ts +0 -0
  31. /package/{projects/ngx-mat-searchable-select/src → src}/public-api.ts +0 -0
  32. /package/{projects/ngx-mat-searchable-select/src → src}/test.ts +0 -0
  33. /package/{projects/ngx-mat-searchable-select/tsconfig.lib.json → tsconfig.lib.json} +0 -0
  34. /package/{projects/ngx-mat-searchable-select/tsconfig.lib.prod.json → tsconfig.lib.prod.json} +0 -0
  35. /package/{projects/ngx-mat-searchable-select/tsconfig.spec.json → tsconfig.spec.json} +0 -0
@@ -1,15 +0,0 @@
1
- /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
2
- /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
3
- {
4
- "extends": "../../tsconfig.json",
5
- "compilerOptions": {
6
- "outDir": "../../out-tsc/spec",
7
- "types": [
8
- "vitest/globals"
9
- ]
10
- },
11
- "include": [
12
- "src/**/*.d.ts",
13
- "src/**/*.spec.ts"
14
- ]
15
- }
@@ -1,262 +0,0 @@
1
- # ngx-mat-searchable-select
2
-
3
- A reusable Angular Material select component with **infinite scroll**, **debounced search**, **"no items found" feedback**, and **static/mock data support** — built with Angular 21 standalone components and signals.
4
-
5
- ## Features
6
-
7
- - Infinite scroll pagination for large server-side datasets
8
- - Debounced search with a sticky search bar, search icon, and clear button
9
- - "No items found" message when search returns no results
10
- - Single and multiple selection
11
- - Edit mode — keeps the pre-selected item visible even when not in the loaded page
12
- - Static items input — no server required for demos and tests
13
- - Built-in `MockSearchableSelectDataSource` for development and unit tests
14
- - Font icon and SVG icon support (no icon registration required for font icons)
15
- - Fully standalone, signal-based, zoneless-ready
16
-
17
- ## Requirements
18
-
19
- - Angular `^21.1.0`
20
- - Angular Material `^21.1.0`
21
- - RxJS `~7.8.0`
22
-
23
- ## Installation
24
-
25
- ```bash
26
- npm install ngx-mat-searchable-select
27
- ```
28
-
29
- ## Quick Start
30
-
31
- ### Option A — Static items (no backend needed)
32
-
33
- ```typescript
34
- import { Component, inject } from '@angular/core';
35
- import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
36
- import {
37
- NgxMatSearchableSelectComponent,
38
- SearchableSelectConfig,
39
- } from 'ngx-mat-searchable-select';
40
-
41
- @Component({
42
- selector: 'app-example',
43
- standalone: true,
44
- imports: [ReactiveFormsModule, NgxMatSearchableSelectComponent],
45
- template: `
46
- <ngx-mat-searchable-select
47
- [parentForm]="form"
48
- [config]="config"
49
- [staticItems]="cities"
50
- (selectionChange)="onSelect($event)"
51
- />
52
- `,
53
- })
54
- export class ExampleComponent {
55
- form = inject(FormBuilder).group({
56
- city: [null, Validators.required],
57
- });
58
-
59
- cities = [
60
- { id: 1, name: 'Paris' },
61
- { id: 2, name: 'London' },
62
- { id: 3, name: 'Berlin' },
63
- ];
64
-
65
- config: SearchableSelectConfig = {
66
- option: {
67
- label: 'City',
68
- formControlName: 'city',
69
- displayName: 'name',
70
- isRequired: true,
71
- fontIcon: 'location_city',
72
- },
73
- mode: 'create',
74
- searchable: true,
75
- };
76
-
77
- onSelect(event: any) {
78
- console.log('Selected:', event.value);
79
- }
80
- }
81
- ```
82
-
83
- ### Option B — Server-driven with pagination
84
-
85
- ```typescript
86
- import { Injectable, inject } from '@angular/core';
87
- import { HttpClient } from '@angular/common/http';
88
- import { Observable } from 'rxjs';
89
- import {
90
- SearchableSelectDataSource,
91
- PagedRequest,
92
- PagedResponse,
93
- } from 'ngx-mat-searchable-select';
94
-
95
- @Injectable({ providedIn: 'root' })
96
- export class CityService implements SearchableSelectDataSource {
97
- private http = inject(HttpClient);
98
-
99
- getAll(request: PagedRequest): Observable<PagedResponse<Record<string, unknown>>> {
100
- return this.http.get<PagedResponse<Record<string, unknown>>>('/api/cities', {
101
- params: {
102
- skip: request.skip,
103
- take: request.take,
104
- search: request.searchString,
105
- },
106
- });
107
- }
108
- }
109
- ```
110
-
111
- Then in your component:
112
-
113
- ```typescript
114
- config: SearchableSelectConfig = {
115
- dataSource: inject(CityService),
116
- option: {
117
- label: 'City',
118
- formControlName: 'city',
119
- displayName: 'name',
120
- isRequired: true,
121
- fontIcon: 'location_city',
122
- },
123
- mode: 'create',
124
- searchable: true,
125
- };
126
- ```
127
-
128
- ### Option C — Edit mode (pre-selected value)
129
-
130
- When `mode: 'edit'` and the pre-selected item may not be on the first loaded page,
131
- the component automatically shows it as an extra option at the top.
132
-
133
- ```typescript
134
- config: SearchableSelectConfig = {
135
- dataSource: inject(CityService),
136
- option: {
137
- label: 'City',
138
- formControlName: 'city',
139
- displayName: 'name',
140
- isRequired: true,
141
- fontIcon: 'location_city',
142
- currentId: 42, // the pre-selected item's id
143
- currentLabel: 'Madrid', // its display label
144
- },
145
- mode: 'edit',
146
- };
147
- ```
148
-
149
- ## API
150
-
151
- ### Inputs
152
-
153
- | Input | Type | Required | Description |
154
- |---|---|---|---|
155
- | `parentForm` | `FormGroup` | Yes | The parent reactive form that contains the control |
156
- | `config` | `SearchableSelectConfig` | Yes | Component configuration object |
157
- | `staticItems` | `Record<string, unknown>[]` | No | Static item array — bypasses `dataSource` entirely |
158
-
159
- ### Outputs
160
-
161
- | Output | Type | Description |
162
- |---|---|---|
163
- | `selectionChange` | `MatSelectChange` | Emits when the user picks an option |
164
- | `valueChange` | `unknown` | Emits the raw value on every change |
165
-
166
- ### SearchableSelectConfig
167
-
168
- ```typescript
169
- interface SearchableSelectConfig {
170
- dataSource?: SearchableSelectDataSource; // required when staticItems is not provided
171
- option: SearchableSelectOption;
172
- mode: 'create' | 'edit';
173
- filter?: { id?: number }; // extra server-side filter (e.g. parent entity id)
174
- searchable?: boolean; // show search box (default: true)
175
- multiple?: boolean; // allow multi-select (default: false)
176
- }
177
- ```
178
-
179
- ### SearchableSelectOption
180
-
181
- ```typescript
182
- interface SearchableSelectOption {
183
- isRequired: boolean; // mark the field as required
184
- displayName: string; // property key used to display each item (e.g. 'name')
185
- formControlName: string; // form control name in the parent FormGroup
186
- label: string; // dropdown label text
187
- svgIcon?: string; // Material SVG icon name (requires MatIconRegistry)
188
- fontIcon?: string; // Material font icon name (no registration needed)
189
- currentId?: number; // pre-selected item id (edit mode)
190
- currentLabel?: string; // pre-selected item label (edit mode)
191
- }
192
- ```
193
-
194
- > **Icon usage:** Use `fontIcon` for quick setup with [Material Icons](https://fonts.google.com/icons) (just include the font link in your `index.html`). Use `svgIcon` when you have custom SVG icons registered via `MatIconRegistry`. Both are optional — if neither is set, no prefix icon is shown.
195
-
196
- ### SearchableSelectDataSource
197
-
198
- ```typescript
199
- interface SearchableSelectDataSource {
200
- getAll(request: PagedRequest): Observable<PagedResponse<Record<string, unknown>>>;
201
- }
202
-
203
- interface PagedRequest {
204
- skip: number;
205
- take: number;
206
- searchString: string;
207
- sort?: string;
208
- id?: number;
209
- }
210
-
211
- interface PagedResponse<T> {
212
- data: T[];
213
- totalCount: number;
214
- }
215
- ```
216
-
217
- ## MockSearchableSelectDataSource
218
-
219
- For use in demos, StackBlitz, and unit tests:
220
-
221
- ```typescript
222
- import { MockSearchableSelectDataSource } from 'ngx-mat-searchable-select';
223
-
224
- const dataSource = new MockSearchableSelectDataSource([
225
- { id: 1, name: 'Paris' },
226
- { id: 2, name: 'London' },
227
- ]);
228
-
229
- config: SearchableSelectConfig = {
230
- dataSource,
231
- option: { ... },
232
- mode: 'create',
233
- };
234
- ```
235
-
236
- `MockSearchableSelectDataSource` supports:
237
- - Pagination via `skip` / `take`
238
- - Full-text search across all string-coercible fields
239
-
240
- ## Migration from v1
241
-
242
- | v1 | v2 |
243
- |---|---|
244
- | `mat-list-shared` (npm) | `ngx-mat-searchable-select` |
245
- | `<lib-mat-list-shared>` | `<ngx-mat-searchable-select>` |
246
- | `MatListSharedComponent` | `NgxMatSearchableSelectComponent` |
247
- | `MatListSharedModule` | removed — import component directly |
248
- | `CustomMatList` class | `SearchableSelectConfig` interface |
249
- | `IMatListService` | `SearchableSelectDataSource` |
250
- | `IMatListOption` | `SearchableSelectOption` |
251
- | `IPagedMatListRequestDto` | `PagedRequest` |
252
- | `[reservedForm]` | `[parentForm]` |
253
- | `[matList]` | `[config]` |
254
- | `option.text` | `option.label` |
255
- | `option.svgIcon` (required) | `option.svgIcon` or `option.fontIcon` (both optional) |
256
- | `option.optionId` | `option.currentId` |
257
- | `option.optionLibelle` | `option.currentLabel` |
258
- | `searchAble` | `searchable` |
259
- | `isMultiSelect` | `multiple` |
260
- | `typeAction` | `mode` |
261
- | `filtre` | `filter` |
262
- | `service` | `dataSource` |
@@ -1,12 +0,0 @@
1
- {
2
- "name": "ngx-mat-searchable-select",
3
- "version": "2.0.0",
4
- "license": "MIT",
5
- "peerDependencies": {
6
- "@angular/common": "^21.1.3",
7
- "@angular/core": "^21.1.3",
8
- "@angular/forms": "^21.1.3",
9
- "@angular/material": "^21.1.3",
10
- "rxjs": "~7.8.0"
11
- }
12
- }
package/tsconfig.json DELETED
@@ -1,39 +0,0 @@
1
- /* To learn more about this file see: https://angular.io/config/tsconfig. */
2
- {
3
- "compileOnSave": false,
4
- "compilerOptions": {
5
- "baseUrl": "./",
6
- "outDir": "./dist/out-tsc",
7
- "forceConsistentCasingInFileNames": true,
8
- "strict": true,
9
- "noImplicitOverride": true,
10
- "noPropertyAccessFromIndexSignature": true,
11
- "noImplicitReturns": true,
12
- "paths": {
13
- "ngx-mat-searchable-select": [
14
- "projects/ngx-mat-searchable-select/src/public-api"
15
- ]
16
- },
17
- "noFallthroughCasesInSwitch": true,
18
- "sourceMap": true,
19
- "declaration": false,
20
- "downlevelIteration": true,
21
- "experimentalDecorators": true,
22
- "moduleResolution": "bundler",
23
- "importHelpers": true,
24
- "target": "ES2022",
25
- "module": "es2020",
26
- "useDefineForClassFields": false
27
- },
28
- "angularCompilerOptions": {
29
- "enableI18nLegacyMessageIdFormat": false,
30
- "strictInjectionParameters": true,
31
- "strictInputAccessModifiers": true,
32
- "strictTemplates": true
33
- },
34
- "references": [
35
- {
36
- "path": "./projects/demo/tsconfig.app.json"
37
- }
38
- ]
39
- }