Skip to content

Commit b23f630

Browse files
authored
feat(select): add selectlabel (#278)
1 parent ea5205b commit b23f630

File tree

8 files changed

+82
-4
lines changed

8 files changed

+82
-4
lines changed

projects/docs/src/app/examples/select/show-case-select/show-case-select.component.html

+16
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,19 @@
3636
</app-option-group>
3737
}
3838
</app-select>
39+
40+
<p class="mt-4 mb-2">Custom label</p>
41+
<app-select
42+
[formControl]="customLabelControl"
43+
placeholder="Custom Label"
44+
class="w-[250px]"
45+
>
46+
<ng-template appSelectLabel let-options>
47+
<ng-icon [svg]="options[0].value()"></ng-icon> {{ options[0].content }}
48+
</ng-template>
49+
@for (option of customOptions; track $index) {
50+
<app-option [value]="option.value">
51+
<ng-icon [svg]="option.value"></ng-icon> {{ option.label }}</app-option
52+
>
53+
}
54+
</app-select>

projects/docs/src/app/examples/select/show-case-select/show-case-select.component.ts

+18
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ import { OptionComponent } from '@/ui/select/option.component';
44
import { SelectComponent } from '@/ui/select/select.component';
55
import { Component } from '@angular/core';
66
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
7+
import { NgIcon } from '@ng-icons/core';
8+
import {
9+
matBlender,
10+
matElectricBolt,
11+
matIron,
12+
} from '@ng-icons/material-icons/baseline';
13+
import { SelectLabelDirective } from '../../../../../../ngverse/src/lib/select/select-label.directive';
714
const countries = [
815
{ code: 'KA', name: 'Georgia' },
916
{ code: 'US', name: 'United States' },
@@ -53,6 +60,12 @@ const directories = [
5360
},
5461
];
5562

63+
const customOptions = [
64+
{ label: 'Electricity', value: matElectricBolt },
65+
{ label: 'Blender', value: matBlender },
66+
{ label: 'Iron', value: matIron },
67+
];
68+
5669
@Component({
5770
selector: 'doc-show-case-select',
5871
imports: [
@@ -61,16 +74,21 @@ const directories = [
6174
OptionComponent,
6275
OptionGroupComponent,
6376
OptionGroupLabelComponent,
77+
SelectLabelDirective,
78+
NgIcon,
6479
],
6580
templateUrl: './show-case-select.component.html',
6681
styleUrl: './show-case-select.component.css',
6782
})
6883
export class ShowCaseSelectComponent {
6984
countries = countries;
7085
directories = directories;
86+
customOptions = customOptions;
7187
formControlSingle = new FormControl(null, Validators.required);
7288

7389
formControlMulti = new FormControl(['US', 'CA'], Validators.required);
7490

7591
dirFormControl = new FormControl(null);
92+
93+
customLabelControl = new FormControl(null);
7694
}

projects/docs/src/app/features/select-page/select-page.component.ts

+7
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ export class SelectPageComponent {
114114
},
115115
],
116116
},
117+
{
118+
name: 'SelectLabelDirective',
119+
type: 'directive',
120+
selector: 'ng-template[appSelectLabel]',
121+
description:
122+
'The label of the select, you can use this directive instead of label input, when you need more customization. The template context will be the options array',
123+
},
117124
{
118125
name: 'OptionGroupComponent',
119126
type: 'component',

projects/docs/src/tree-structure.json

+10
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,16 @@
893893
"name": "option.component.ts",
894894
"language": "ts"
895895
},
896+
{
897+
"path": "select/select-label.directive.spec.ts",
898+
"name": "select-label.directive.spec.ts",
899+
"language": "spec.ts"
900+
},
901+
{
902+
"path": "select/select-label.directive.ts",
903+
"name": "select-label.directive.ts",
904+
"language": "ts"
905+
},
896906
{
897907
"path": "select/select.component.css",
898908
"name": "select.component.css",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Directive, inject, TemplateRef } from '@angular/core';
2+
3+
@Directive({
4+
selector: 'ng-template[appSelectLabel]',
5+
})
6+
export class SelectLabelDirective {
7+
templateRef = inject(TemplateRef<unknown>);
8+
}

projects/ngverse/src/lib/select/select.component.html

+16-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,22 @@
66
(click)="togglePanel()"
77
[disabled]="disabled()"
88
>
9-
<span class="flex-1 truncate text-left">{{
10-
selectedOptionsLabel() || placeholder()
11-
}}</span>
9+
<span class="flex-1 truncate text-left">
10+
@if (selectedOptionsLabel(); as selectedOptionsLabel) {
11+
@if (templateLabel(); as templateLabel) {
12+
<ng-container
13+
*ngTemplateOutlet="
14+
templateLabel.templateRef;
15+
context: { $implicit: selectedOptions() }
16+
"
17+
></ng-container>
18+
} @else {
19+
{{ selectedOptionsLabel }}
20+
}
21+
} @else {
22+
{{ placeholder() }}
23+
}
24+
</span>
1225
<ng-icon
1326
class="transition-transform"
1427
[class.rotate-180]="isOpen()"

projects/ngverse/src/lib/select/select.component.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ describe('SelectComponent', () => {
7070
it('should display placeholder text when no value is selected', async () => {
7171
await fixture.whenStable();
7272
const selectButtonLabel = fixture.nativeElement.querySelector('span');
73-
expect(selectButtonLabel.textContent).toBe('Select a country');
73+
expect(selectButtonLabel.textContent.trim()).toBe('Select a country');
7474
});
7575

7676
it('should display selected value label', async () => {

projects/ngverse/src/lib/select/select.component.ts

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
ChangeDetectionStrategy,
33
Component,
44
computed,
5+
contentChild,
56
contentChildren,
67
ElementRef,
78
forwardRef,
@@ -22,11 +23,13 @@ import { PopoverOriginDirective } from '@/ui/popover/popover-origin.directive';
2223
import { PopoverComponent } from '@/ui/popover/popover.component';
2324
import { ActiveDescendantKeyManager } from '@angular/cdk/a11y';
2425
import { SelectionModel } from '@angular/cdk/collections';
26+
import { NgTemplateOutlet } from '@angular/common';
2527
import { toSignal } from '@angular/core/rxjs-interop';
2628
import { NgIcon } from '@ng-icons/core';
2729
import { matExpandMore } from '@ng-icons/material-icons/baseline';
2830
import { map } from 'rxjs';
2931
import { OptionComponent } from './option.component';
32+
import { SelectLabelDirective } from './select-label.directive';
3033

3134
type OnTouchedFunction = (() => void) | undefined;
3235

@@ -42,6 +45,7 @@ export type CompareWith = (o1: any, o2: any) => boolean;
4245
PopoverOriginDirective,
4346
PopoverComponent,
4447
NgIcon,
48+
NgTemplateOutlet,
4549
],
4650
templateUrl: './select.component.html',
4751
styleUrl: './select.component.css',
@@ -73,6 +77,8 @@ export class SelectComponent implements ControlValueAccessor, OnDestroy {
7377
inject(Injector)
7478
).withTypeAhead();
7579

80+
templateLabel = contentChild<SelectLabelDirective>(SelectLabelDirective);
81+
7682
selectOption = viewChild<ElementRef<HTMLElement>>('selectOption');
7783

7884
compareWith = input<CompareWith, CompareWith>(

0 commit comments

Comments
 (0)