Skip to content

Commit 9a66c03

Browse files
feat: content functionality for select option (#1160)
1 parent cd43f63 commit 9a66c03

File tree

8 files changed

+127
-36
lines changed

8 files changed

+127
-36
lines changed

projects/common/src/telemetry/providers/google-analytics/google-analytics-provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Dictionary } from './../../../utilities/types/types';
21
import { TelemetryProviderConfig, UserTelemetryProvider, UserTraits } from '../../telemetry';
2+
import { Dictionary } from './../../../utilities/types/types';
33
import { loadGA } from './load-snippet';
44

55
export class GoogleAnalyticsTelemetry<InitConfig extends TelemetryProviderConfig>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/jest';
2+
import { SelectOptionRendererDirective } from './select-option-renderer.directive';
3+
4+
describe('Select Option Renderer directive', () => {
5+
let spectator: SpectatorDirective<SelectOptionRendererDirective>;
6+
7+
const createDirective = createDirectiveFactory<SelectOptionRendererDirective>({
8+
directive: SelectOptionRendererDirective
9+
});
10+
11+
beforeEach(() => {
12+
spectator = createDirective(`
13+
<div class="content" *htSelectOptionRenderer>content</div>
14+
`);
15+
});
16+
17+
test('should render content', () => {
18+
const content = spectator.directive.getTemplateRef();
19+
expect(content).toExist();
20+
});
21+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Directive, TemplateRef } from '@angular/core';
2+
3+
@Directive({
4+
selector: '[htSelectOptionRenderer]'
5+
})
6+
export class SelectOptionRendererDirective {
7+
public constructor(private readonly templateRef: TemplateRef<unknown>) {}
8+
9+
public getTemplateRef(): TemplateRef<unknown> {
10+
return this.templateRef;
11+
}
12+
}

projects/components/src/select/select-option.component.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
1+
import { ChangeDetectionStrategy, Component, ContentChild, Input, OnChanges } from '@angular/core';
22
import { IconType } from '@hypertrace/assets-library';
33
import { Observable, Subject } from 'rxjs';
44
import { IconBorder } from '../icon/icon-border';
5+
import { SelectOptionRendererDirective } from './directive/select-option-renderer.directive';
56
import { SelectOption } from './select-option';
67

78
@Component({
89
selector: 'ht-select-option',
910
changeDetection: ChangeDetectionStrategy.OnPush,
10-
template: '' // No template, just gathering data
11+
template: ``
1112
})
1213
export class SelectOptionComponent<V> implements OnChanges, SelectOption<V> {
1314
@Input()
@@ -40,6 +41,9 @@ export class SelectOptionComponent<V> implements OnChanges, SelectOption<V> {
4041
@Input()
4142
public disabled?: boolean;
4243

44+
@ContentChild(SelectOptionRendererDirective)
45+
public selectOptionRenderer?: SelectOptionRendererDirective;
46+
4347
private readonly optionChangeSubject$: Subject<V> = new Subject<V>();
4448
public readonly optionChange$: Observable<V> = this.optionChangeSubject$.asObservable();
4549

projects/components/src/select/select-option.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export interface SelectOption<V> {
22
value: V;
3-
label: string;
3+
label?: string;
44
selectedLabel?: string;
55
icon?: string;
66
iconColor?: string;

projects/components/src/select/select.component.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,26 @@ describe('Select Component', () => {
6060
expect(spectator.element).toHaveText(selectionOptions[2].label);
6161
}));
6262

63+
test('should display initial selection for new select renderer', fakeAsync(() => {
64+
spectator = hostFactory(
65+
`
66+
<ht-select [selected]="selected">
67+
<ht-select-option *ngFor="let option of options; let i = index" [label]="option.label" [value]="option.value">
68+
<div *htSelectOptionRenderer>new-label</div>
69+
</ht-select-option>
70+
</ht-select>`,
71+
{
72+
hostProps: {
73+
options: selectionOptions,
74+
selected: selectionOptions[1].value
75+
}
76+
}
77+
);
78+
spectator.tick();
79+
80+
expect(spectator.element).toHaveText('new-label');
81+
}));
82+
6383
test('should display provided options when clicked', fakeAsync(() => {
6484
spectator = hostFactory(
6585
`

projects/components/src/select/select.component.ts

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,28 @@ import { SelectSize } from './select-size';
5555
class="trigger-content menu-with-border"
5656
[ngClass]="[this.justifyClass]"
5757
>
58-
<ht-icon
59-
*ngIf="this.getPrefixIcon(selected)"
60-
class="trigger-prefix-icon"
61-
[icon]="this.getPrefixIcon(selected)"
62-
[size]="this.iconSize"
63-
[color]="selected?.iconColor"
64-
[borderType]="selected?.iconBorderType"
65-
[borderColor]="selected?.iconBorderColor"
66-
[borderRadius]="selected?.iconBorderRadius"
67-
>
68-
</ht-icon>
69-
<ht-label class="trigger-label" [label]="selected?.selectedLabel || selected?.label || this.placeholder">
70-
</ht-label>
58+
<ng-container
59+
[ngTemplateOutlet]="selected?.selectOptionRenderer?.getTemplateRef() ?? defaultMenuWithBorderTriggerTemplate"
60+
></ng-container>
7161
<ht-icon class="trigger-icon" icon="${IconType.ChevronDown}" size="${IconSize.ExtraSmall}"> </ht-icon>
62+
<ng-template #defaultMenuWithBorderTriggerTemplate
63+
><ht-icon
64+
*ngIf="this.getPrefixIcon(selected)"
65+
class="trigger-prefix-icon"
66+
[icon]="this.getPrefixIcon(selected)"
67+
[size]="this.iconSize"
68+
[color]="selected?.iconColor"
69+
[borderType]="selected?.iconBorderType"
70+
[borderColor]="selected?.iconBorderColor"
71+
[borderRadius]="selected?.iconBorderRadius"
72+
>
73+
</ht-icon>
74+
<ht-label
75+
class="trigger-label"
76+
[label]="selected?.selectedLabel || selected?.label || this.placeholder"
77+
>
78+
</ht-label>
79+
</ng-template>
7280
</div>
7381
<div
7482
*ngSwitchCase="'${SelectTriggerDisplayMode.Icon}'"
@@ -89,8 +97,16 @@ import { SelectSize } from './select-size';
8997
class="trigger-content menu-with-background"
9098
[ngClass]="[this.justifyClass]"
9199
>
92-
<ht-label class="trigger-label" [label]="selected?.selectedLabel || selected?.label || this.placeholder">
93-
</ht-label>
100+
<ng-container
101+
[ngTemplateOutlet]="selected?.selectOptionRenderer?.getTemplateRef() ?? defaultMenuWithBackgroundTriggerTemplate"
102+
></ng-container>
103+
<ng-template #defaultMenuWithBackgroundTriggerTemplate
104+
><<ht-label
105+
class="trigger-label"
106+
[label]="selected?.selectedLabel || selected?.label || this.placeholder"
107+
>
108+
</ht-label
109+
></ng-template>
94110
<ht-icon class="trigger-icon" icon="${IconType.ChevronDown}" size="${IconSize.Small}"> </ht-icon>
95111
</div>
96112
</div>
@@ -111,28 +127,16 @@ import { SelectSize } from './select-size';
111127
*ngTemplateOutlet="itemsTemplate; context: { items: items, showSelectionStatus: true }"
112128
></ng-container>
113129
</div>
114-
115130
<ng-template #itemsTemplate let-items="items" let-showSelectionStatus="showSelectionStatus">
116131
<div
117132
*ngFor="let item of items"
118133
(click)="this.onSelectionChange(item)"
119134
class="select-option"
120135
[ngClass]="this.getStyleClassesForSelectItem | htMemoize: this.size:item"
121136
>
122-
<div class="select-option-info">
123-
<ht-icon
124-
*ngIf="item.icon"
125-
class="icon"
126-
[icon]="item.icon"
127-
size="${IconSize.Small}"
128-
[color]="item.iconColor"
129-
[borderType]="item?.iconBorderType"
130-
[borderColor]="item?.iconBorderColor"
131-
[borderRadius]="item?.iconBorderRadius"
132-
>
133-
</ht-icon>
134-
<span class="label">{{ item.label }}</span>
135-
</div>
137+
<ng-container
138+
*ngTemplateOutlet="item.selectOptionRenderer?.getTemplateRef() ?? defaultSelectOptionTemplate; context: {$implicit: item}"
139+
></ng-container>
136140
<ht-icon
137141
class="status-icon"
138142
*ngIf="showSelectionStatus && this.highlightSelected && this.isSelectedItem(item)"
@@ -141,6 +145,23 @@ import { SelectSize } from './select-size';
141145
></ht-icon>
142146
</div>
143147
</ng-template>
148+
149+
<ng-template #defaultSelectOptionTemplate let-item
150+
><div class="select-option-info">
151+
<ht-icon
152+
*ngIf="item.icon"
153+
class="icon"
154+
[icon]="item.icon"
155+
size="${IconSize.Small}"
156+
[color]="item.iconColor"
157+
[borderType]="item?.iconBorderType"
158+
[borderColor]="item?.iconBorderColor"
159+
[borderRadius]="item?.iconBorderRadius"
160+
>
161+
</ht-icon>
162+
<span class="label">{{ item.label }}</span>
163+
</div>
164+
</ng-template>
144165
</ht-popover-content>
145166
</ht-popover>
146167
</div>

projects/components/src/select/select.module.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { LabelModule } from '../label/label.module';
88
import { LetAsyncModule } from '../let-async/let-async.module';
99
import { PopoverModule } from '../popover/popover.module';
1010
import { TooltipModule } from '../tooltip/tooltip.module';
11+
import { SelectOptionRendererDirective } from './directive/select-option-renderer.directive';
1112
import { SelectControlOptionComponent } from './select-control-option.component';
1213
import { SelectGroupComponent } from './select-group.component';
1314
import { SelectOptionComponent } from './select-option.component';
@@ -25,7 +26,19 @@ import { SelectComponent } from './select.component';
2526
DividerModule,
2627
MemoizeModule
2728
],
28-
declarations: [SelectComponent, SelectOptionComponent, SelectGroupComponent, SelectControlOptionComponent],
29-
exports: [SelectComponent, SelectOptionComponent, SelectGroupComponent, SelectControlOptionComponent]
29+
declarations: [
30+
SelectComponent,
31+
SelectOptionComponent,
32+
SelectGroupComponent,
33+
SelectControlOptionComponent,
34+
SelectOptionRendererDirective
35+
],
36+
exports: [
37+
SelectComponent,
38+
SelectOptionComponent,
39+
SelectGroupComponent,
40+
SelectControlOptionComponent,
41+
SelectOptionRendererDirective
42+
]
3043
})
3144
export class SelectModule {}

0 commit comments

Comments
 (0)