0
# Form Components
1
2
Enhanced form controls including rating, timepicker, and typeahead components with full Angular forms integration and accessibility support.
3
4
## Core Imports
5
6
```typescript
7
import {
8
NgbRatingModule,
9
NgbTimepickerModule,
10
NgbTypeaheadModule
11
} from '@ng-bootstrap/ng-bootstrap';
12
```
13
14
## Capabilities
15
16
### NgbRating
17
18
Star rating component with customizable appearance and behavior.
19
20
```typescript { .api }
21
@Component({
22
selector: 'ngb-rating',
23
exportAs: 'ngbRating'
24
})
25
class NgbRating implements ControlValueAccessor {
26
/** Maximum rating value */
27
@Input() max: number;
28
29
/** Current rating value */
30
@Input() rate: number;
31
32
/** If true, rating is readonly */
33
@Input() readonly: boolean;
34
35
/** If true, allows resetting to 0 by clicking current rate */
36
@Input() resettable: boolean;
37
38
/** Template for custom star appearance */
39
@Input() starTemplate: TemplateRef<StarTemplateContext>;
40
41
/** Event emitted when hovering over a star */
42
@Output() hover: EventEmitter<number>;
43
44
/** Event emitted when mouse leaves the rating */
45
@Output() leave: EventEmitter<number>;
46
47
/** Event emitted when rating changes */
48
@Output() rateChange: EventEmitter<number>;
49
50
/** Reset rating to 0 */
51
reset(): void;
52
53
/** Update rating value */
54
update(value: number): void;
55
}
56
```
57
58
### NgbTimepicker
59
60
Time picker component for hour, minute, and second selection.
61
62
```typescript { .api }
63
@Component({
64
selector: 'ngb-timepicker',
65
exportAs: 'ngbTimepicker'
66
})
67
class NgbTimepicker implements ControlValueAccessor {
68
/** If true, display 12-hour format with AM/PM */
69
@Input() meridian: boolean;
70
71
/** If true, show spinner buttons */
72
@Input() spinners: boolean;
73
74
/** If true, show seconds input */
75
@Input() seconds: boolean;
76
77
/** Hour step for spinner buttons */
78
@Input() hourStep: number;
79
80
/** Minute step for spinner buttons */
81
@Input() minuteStep: number;
82
83
/** Second step for spinner buttons */
84
@Input() secondStep: number;
85
86
/** If true, inputs are readonly */
87
@Input() readonlyInputs: boolean;
88
89
/** Size of the timepicker */
90
@Input() size: 'small' | 'medium' | 'large';
91
92
/** Navigate to specific time */
93
navigateTime(step: number): void;
94
}
95
```
96
97
### NgbTypeahead
98
99
Autocomplete/typeahead directive providing powerful search functionality for input elements.
100
101
```typescript { .api }
102
@Directive({
103
selector: 'input[ngbTypeahead]',
104
exportAs: 'ngbTypeahead'
105
})
106
class NgbTypeahead implements ControlValueAccessor {
107
/** Autocomplete attribute for the input */
108
@Input() autocomplete: string;
109
110
/** Container element for the dropdown */
111
@Input() container: string;
112
113
/** If false, selected value cannot be edited */
114
@Input() editable: boolean;
115
116
/** If true, first item will be focused automatically */
117
@Input() focusFirst: boolean;
118
119
/** Function to format selected item in input field */
120
@Input() inputFormatter: (item: any) => string;
121
122
/** Operator function that provides search suggestions */
123
@Input() ngbTypeahead: OperatorFunction<string, readonly any[]> | null | undefined;
124
125
/** Function to format items in result list */
126
@Input() resultFormatter: (item: any) => string;
127
128
/** Custom template for result items */
129
@Input() resultTemplate: TemplateRef<ResultTemplateContext>;
130
131
/** If true, selects item on exact match */
132
@Input() selectOnExact: boolean;
133
134
/** If true, shows hint with first match */
135
@Input() showHint: boolean;
136
137
/** Preferred placement of dropdown */
138
@Input() placement: PlacementArray;
139
140
/** Popper options modifier function */
141
@Input() popperOptions: (options: Partial<Options>) => Partial<Options>;
142
143
/** CSS class for dropdown popup */
144
@Input() popupClass: string;
145
146
/** Event emitted when item is selected */
147
@Output() selectItem: EventEmitter<NgbTypeaheadSelectItemEvent>;
148
149
/** Active descendant for accessibility */
150
activeDescendant: string | null;
151
152
/** Popup window ID */
153
popupId: string;
154
155
/** Dismiss the typeahead popup */
156
dismissPopup(): void;
157
158
/** Check if popup is open */
159
isPopupOpen(): boolean;
160
}
161
```
162
163
### NgbHighlight
164
165
Component for highlighting search terms within text results.
166
167
```typescript { .api }
168
@Component({
169
selector: 'ngb-highlight',
170
exportAs: 'ngbHighlight'
171
})
172
class NgbHighlight {
173
/** CSS class for highlighted spans (default: 'ngb-highlight') */
174
@Input() highlightClass: string;
175
176
/** Text to add highlighting to (required) */
177
@Input({ required: true }) result?: string | null;
178
179
/** Term or terms to highlight (required) */
180
@Input({ required: true }) term: string | readonly string[];
181
182
/** If true, highlighting is accent-sensitive */
183
@Input() accentSensitive: boolean;
184
185
/** Array of text parts after processing */
186
parts: string[];
187
}
188
```
189
190
### Configuration Services
191
192
```typescript { .api }
193
@Injectable({ providedIn: 'root' })
194
class NgbRatingConfig {
195
/** Default maximum rating */
196
max: number;
197
198
/** Default readonly state */
199
readonly: boolean;
200
201
/** Default resettable state */
202
resettable: boolean;
203
}
204
205
@Injectable({ providedIn: 'root' })
206
class NgbTimepickerConfig {
207
/** Default meridian setting */
208
meridian: boolean;
209
210
/** Default spinners setting */
211
spinners: boolean;
212
213
/** Default seconds setting */
214
seconds: boolean;
215
216
/** Default hour step */
217
hourStep: number;
218
219
/** Default minute step */
220
minuteStep: number;
221
222
/** Default second step */
223
secondStep: number;
224
225
/** Default disabled state */
226
disabled: boolean;
227
228
/** Default readonly inputs state */
229
readonlyInputs: boolean;
230
231
/** Default size */
232
size: 'small' | 'medium' | 'large';
233
}
234
235
@Injectable({ providedIn: 'root' })
236
class NgbTypeaheadConfig {
237
/** Default container */
238
container: string;
239
240
/** Default editor formatter */
241
editable: boolean;
242
243
/** Default focus first */
244
focusFirst: boolean;
245
246
/** Default show hint */
247
showHint: boolean;
248
249
/** Default placement */
250
placement: PlacementArray;
251
}
252
```
253
254
## Type Definitions
255
256
```typescript { .api }
257
interface NgbTimeStruct {
258
hour: number;
259
minute: number;
260
second: number;
261
}
262
263
interface NgbTypeaheadSelectItemEvent {
264
/** Selected item */
265
item: any;
266
267
/** Prevent default selection behavior */
268
preventDefault: () => void;
269
}
270
271
interface StarTemplateContext {
272
/** Star value/index */
273
$implicit: number;
274
275
/** Current fill percentage (0-100) */
276
fill: number;
277
278
/** Star index */
279
index: number;
280
}
281
282
interface ResultTemplateContext {
283
/** Search result item */
284
$implicit: any;
285
286
/** Search term */
287
term: string;
288
289
/** Formatter function */
290
formatter: (item: any) => string;
291
}
292
```
293
294
## Usage Examples
295
296
### Basic Rating Component
297
298
```typescript
299
@Component({
300
template: `
301
<div class="mb-3">
302
<label>Rate this item:</label>
303
<ngb-rating
304
[(rate)]="currentRate"
305
[max]="5"
306
[readonly]="false"
307
[resettable]="true"
308
(rateChange)="onRateChange($event)">
309
</ngb-rating>
310
<p>Current rating: {{ currentRate }}</p>
311
</div>
312
`
313
})
314
export class BasicRatingComponent {
315
currentRate = 3;
316
317
onRateChange(rate: number) {
318
console.log('Rating changed to:', rate);
319
}
320
}
321
```
322
323
### Custom Star Template
324
325
```typescript
326
@Component({
327
template: `
328
<ngb-rating
329
[(rate)]="currentRate"
330
[starTemplate]="customStar">
331
</ngb-rating>
332
333
<ng-template #customStar let-fill="fill" let-index="index">
334
<span class="custom-star" [class.filled]="fill === 100">
335
<i class="bi" [class.bi-heart-fill]="fill === 100" [class.bi-heart]="fill < 100"></i>
336
</span>
337
</ng-template>
338
`
339
})
340
export class CustomStarRatingComponent {
341
currentRate = 2;
342
}
343
```
344
345
### Basic Timepicker
346
347
```typescript
348
@Component({
349
template: `
350
<div class="mb-3">
351
<label>Select time:</label>
352
<ngb-timepicker
353
[(ngModel)]="selectedTime"
354
[meridian]="true"
355
[seconds]="true"
356
[spinners]="true">
357
</ngb-timepicker>
358
<p *ngIf="selectedTime">Selected: {{ selectedTime | json }}</p>
359
</div>
360
`
361
})
362
export class BasicTimepickerComponent {
363
selectedTime: NgbTimeStruct = { hour: 13, minute: 30, second: 0 };
364
}
365
```
366
367
### Reactive Form Integration
368
369
```typescript
370
@Component({
371
template: `
372
<form [formGroup]="timeForm" (ngSubmit)="onSubmit()">
373
<div class="mb-3">
374
<label>Meeting time:</label>
375
<ngb-timepicker
376
formControlName="meetingTime"
377
[meridian]="false"
378
[seconds]="false">
379
</ngb-timepicker>
380
</div>
381
382
<div class="mb-3">
383
<label>Rating:</label>
384
<ngb-rating
385
formControlName="rating"
386
[max]="10">
387
</ngb-rating>
388
</div>
389
390
<button type="submit" class="btn btn-primary" [disabled]="timeForm.invalid">
391
Submit
392
</button>
393
</form>
394
`
395
})
396
export class ReactiveFormComponent implements OnInit {
397
timeForm: FormGroup;
398
399
constructor(private fb: FormBuilder) {}
400
401
ngOnInit() {
402
this.timeForm = this.fb.group({
403
meetingTime: [{ hour: 14, minute: 0, second: 0 }, Validators.required],
404
rating: [5, [Validators.required, Validators.min(1)]]
405
});
406
}
407
408
onSubmit() {
409
if (this.timeForm.valid) {
410
console.log('Form data:', this.timeForm.value);
411
}
412
}
413
}
414
```
415
416
### Basic Typeahead
417
418
```typescript
419
@Component({
420
template: `
421
<div class="mb-3">
422
<label for="typeahead-basic">Search for a state:</label>
423
<input
424
id="typeahead-basic"
425
type="text"
426
class="form-control"
427
[(ngModel)]="selectedState"
428
[ngbTypeahead]="search"
429
placeholder="Type to search...">
430
</div>
431
432
<p *ngIf="selectedState">Selected: {{ selectedState }}</p>
433
`
434
})
435
export class BasicTypeaheadComponent {
436
selectedState: string = '';
437
438
states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California'];
439
440
search = (text$: Observable<string>) =>
441
text$.pipe(
442
debounceTime(200),
443
distinctUntilChanged(),
444
map(term => term.length < 2 ? []
445
: this.states.filter(v => v.toLowerCase().indexOf(term.toLowerCase()) > -1).slice(0, 10))
446
);
447
}
448
```
449
450
### Advanced Typeahead with Template
451
452
```typescript
453
@Component({
454
template: `
455
<div class="mb-3">
456
<label for="typeahead-template">Search users:</label>
457
<input
458
id="typeahead-template"
459
type="text"
460
class="form-control"
461
[(ngModel)]="selectedUser"
462
[ngbTypeahead]="searchUsers"
463
[resultTemplate]="userTemplate"
464
[inputFormatter]="userFormatter"
465
(selectItem)="onUserSelect($event)">
466
</div>
467
468
<ng-template #userTemplate let-user="result" let-term="term">
469
<div class="d-flex align-items-center">
470
<img [src]="user.avatar" class="rounded-circle me-2" width="32" height="32">
471
<div>
472
<div><ngb-highlight [result]="user.name" [term]="term"></ngb-highlight></div>
473
<small class="text-muted">{{ user.email }}</small>
474
</div>
475
</div>
476
</ng-template>
477
`
478
})
479
export class AdvancedTypeaheadComponent {
480
selectedUser: any;
481
482
users = [
483
{ id: 1, name: 'John Doe', email: 'john@example.com', avatar: 'avatar1.jpg' },
484
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', avatar: 'avatar2.jpg' }
485
];
486
487
searchUsers = (text$: Observable<string>) =>
488
text$.pipe(
489
debounceTime(300),
490
distinctUntilChanged(),
491
map(term => term.length < 2 ? []
492
: this.users.filter(user =>
493
user.name.toLowerCase().includes(term.toLowerCase()) ||
494
user.email.toLowerCase().includes(term.toLowerCase())
495
).slice(0, 10))
496
);
497
498
userFormatter = (user: any) => user.name;
499
500
onUserSelect(event: NgbTypeaheadSelectItemEvent) {
501
console.log('User selected:', event.item);
502
}
503
}
504
```