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.
- package/README.md +19 -127
- package/package.json +12 -44
- package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.component.html +75 -75
- package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.mock.ts +43 -43
- package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-select-infinite-scroll.directive.ts +52 -52
- package/.editorconfig +0 -16
- package/.vscode/extensions.json +0 -4
- package/.vscode/launch.json +0 -20
- package/.vscode/tasks.json +0 -42
- package/LICENSE +0 -21
- package/angular.json +0 -151
- package/projects/demo/public/favicon.ico +0 -0
- package/projects/demo/src/app/app.config.ts +0 -9
- package/projects/demo/src/app/app.html +0 -118
- package/projects/demo/src/app/app.scss +0 -64
- package/projects/demo/src/app/app.ts +0 -167
- package/projects/demo/src/index.html +0 -16
- package/projects/demo/src/main.ts +0 -6
- package/projects/demo/src/styles.scss +0 -31
- package/projects/demo/tsconfig.app.json +0 -17
- package/projects/demo/tsconfig.spec.json +0 -15
- package/projects/ngx-mat-searchable-select/README.md +0 -262
- package/projects/ngx-mat-searchable-select/package.json +0 -12
- package/tsconfig.json +0 -39
- /package/{projects/ngx-mat-searchable-select/karma.conf.js → karma.conf.js} +0 -0
- /package/{projects/ngx-mat-searchable-select/ng-package.json → ng-package.json} +0 -0
- /package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.component.spec.ts +0 -0
- /package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.component.ts +0 -0
- /package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.model.ts +0 -0
- /package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.service.spec.ts +0 -0
- /package/{projects/ngx-mat-searchable-select/src → src}/public-api.ts +0 -0
- /package/{projects/ngx-mat-searchable-select/src → src}/test.ts +0 -0
- /package/{projects/ngx-mat-searchable-select/tsconfig.lib.json → tsconfig.lib.json} +0 -0
- /package/{projects/ngx-mat-searchable-select/tsconfig.lib.prod.json → tsconfig.lib.prod.json} +0 -0
- /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
|
-
}
|
|
File without changes
|
|
File without changes
|
/package/{projects/ngx-mat-searchable-select/src → src}/lib/mat-list-shared.component.spec.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/{projects/ngx-mat-searchable-select/tsconfig.lib.prod.json → tsconfig.lib.prod.json}
RENAMED
|
File without changes
|
|
File without changes
|