Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
feat(select): Allow custom template for selected value
Browse files Browse the repository at this point in the history
  • Loading branch information
yngrdyn authored and tomheller committed Nov 12, 2020
1 parent 9f0130a commit 7621940
Show file tree
Hide file tree
Showing 15 changed files with 213 additions and 15 deletions.
5 changes: 5 additions & 0 deletions apps/demos/src/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ import {
DtExampleTreeTableSimple,
DtExampleComboboxCustomOptionHeight,
DtExampleFilterFieldInfiniteDataDepth,
DtExampleSelectCustomValueTemplate,
} from '@dynatrace/examples';

// The Routing Module replaces the routing configuration in the root or feature module.
Expand Down Expand Up @@ -1157,6 +1158,10 @@ const ROUTES: Routes = [
component: DtExampleTreeTableProblemIndicator,
},
{ path: 'tree-table-simple-example', component: DtExampleTreeTableSimple },
{
path: 'select-custom-value-template-example',
component: DtExampleSelectCustomValueTemplate,
},
];

@NgModule({
Expand Down
1 change: 1 addition & 0 deletions apps/demos/src/barista-examples.a11y.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const BLOCKLIST: string[] = [
'select-groups-example',
'select-value-example',
'select-with-icons-example',
'select-custom-value-template-example',

// Disabled the filter field tests, because their `combobox` role does not
// fulfil all requirements of a combobox.
Expand Down
4 changes: 4 additions & 0 deletions apps/demos/src/nav-items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,10 @@ export const DT_DEMOS_EXAMPLE_NAV_ITEMS = [
name: 'select-with-icons-example',
route: '/select-with-icons-example',
},
{
name: 'select-custom-value-template-example',
route: '/select-custom-value-template-example',
},
],
},
{
Expand Down
30 changes: 19 additions & 11 deletions libs/barista-components/select/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ in the Angular forms documentation).

## DtSelect inputs

| Name | Type | Description |
| ------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `placeholder` | `string` | Placeholder to be shown if no value has been selected. |
| `required` | `boolean` | Whether the component is required. |
| `compareWith` | `(v1: T, v2: T) => boolean` | Function to compare the option values with the selected values. The first argument is a value from an option. The second is a value from the selection. A boolean should be returned. Defaults to value equality. |
| `value` | `T` | Value of the select control. |
| `id` | `string` | Unique id of the element. |
| `aria-label` | `string` | Aria label of the select. If not specified, the placeholder will be used as label. |
| `aria-labelledby` | `string` | Input that can be used to specify the `aria-labelledby` attribute. |
| `errorStateMatcher` | `ErrorStateMatcher` | Object used to control when error messages are shown. |
| `panelClass` | `string | string[] | Set<string> | { [key: string]: any }` | Classes to be passed to the select panel. Supports the same syntax as `ngClass`. |
| Name | Type | Description |
| ------------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `placeholder` | `string` | Placeholder to be shown if no value has been selected. |
| `required` | `boolean` | Whether the component is required. |
| `compareWith` | `(v1: T, v2: T) => boolean` | Function to compare the option values with the selected values. The first argument is a value from an option. The second is a value from the selection. A boolean should be returned. Defaults to value equality. |
| `value` | `T` | Value of the select control. |
| `id` | `string` | Unique id of the element. |
| `aria-label` | `string` | Aria label of the select. If not specified, the placeholder will be used as label. |
| `aria-labelledby` | `string` | Input that can be used to specify the `aria-labelledby` attribute. |
| `errorStateMatcher` | `ErrorStateMatcher` | Object used to control when error messages are shown. |
| `panelClass` | `string | string[] | Set<string> | { [key: string]: any }` | Classes to be passed to the select panel. Supports the same syntax as `ngClass`. |

## DtSelect outputs

Expand Down Expand Up @@ -119,6 +119,14 @@ select.

<ba-live-example name="DtExampleSelectWithIcons"></ba-live-example>

## Custom trigger

It is possible to customize the trigger that is displayed when the select has a
value. By using the property `<dt-select-value-template>` it's possible to
stablish a new template for the selected value.

<ba-live-example name="DtExampleSelectCustomValueTemplate"></ba-live-example>

## Accessibility

The select component without text or label should be given a meaningful label
Expand Down
1 change: 1 addition & 0 deletions libs/barista-components/select/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@

export * from './src/select-module';
export * from './src/select';
export * from './src/select-value-template';
5 changes: 3 additions & 2 deletions libs/barista-components/select/src/select-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ import { DtFormFieldModule } from '@dynatrace/barista-components/form-field';
import { DtIconModule } from '@dynatrace/barista-components/icon';

import { DtSelect } from './select';
import { DtSelectValueTemplate } from './select-value-template';

@NgModule({
imports: [CommonModule, OverlayModule, DtIconModule, DtOptionModule],
exports: [DtFormFieldModule, DtOptionModule, DtSelect],
declarations: [DtSelect],
exports: [DtFormFieldModule, DtOptionModule, DtSelect, DtSelectValueTemplate],
declarations: [DtSelect, DtSelectValueTemplate],
})
export class DtSelectModule {}
29 changes: 29 additions & 0 deletions libs/barista-components/select/src/select-value-template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* @license
* Copyright 2020 Dynatrace LLC
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Component } from '@angular/core';

/**
* Allows the user to customize the trigger that is displayed when the select has a value.
*/
@Component({
selector: 'dt-select-value-template',
template: '<ng-content></ng-content>',
host: {
class: 'dt-select-value-template',
},
})
export class DtSelectValueTemplate {}
12 changes: 10 additions & 2 deletions libs/barista-components/select/src/select.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,16 @@
<span class="dt-select-placeholder" *ngSwitchCase="true">
{{ placeholder || '\u00A0' }}
</span>
<span class="dt-select-value-text" *ngSwitchCase="false">
{{ triggerValue || '\u00A0' }}
<span
class="dt-select-value-text"
*ngSwitchCase="false"
[ngSwitch]="!!_customValueTemplate"
>
<span *ngSwitchDefault>{{ triggerValue || '\u00A0' }}</span>
<ng-content
select="dt-select-value-template"
*ngSwitchCase="true"
></ng-content>
</span>
</div>

Expand Down
80 changes: 80 additions & 0 deletions libs/barista-components/select/src/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import {
createComponent,
createKeyboardEvent,
} from '@dynatrace/testing/browser';
import { DtSelectValueTemplate } from './select-value-template';

describe('DtSelect', () => {
let overlayContainer: OverlayContainer;
Expand Down Expand Up @@ -119,6 +120,7 @@ describe('DtSelect', () => {
SelectWithGroupsAndNgContainer,
SelectWithFormFieldLabel,
SelectWithOptionValueZero,
SelectWithCustomTrigger,
]);
}));

Expand Down Expand Up @@ -684,6 +686,57 @@ describe('DtSelect', () => {
});
});

describe('custom trigger', () => {
let fixture: ComponentFixture<SelectWithCustomTrigger>;
let trigger: HTMLElement;

beforeEach(fakeAsync(() => {
fixture = createComponent(SelectWithCustomTrigger);
trigger = fixture.debugElement.query(By.css('.dt-select-trigger'))
.nativeElement;
}));

it('should be undefined', fakeAsync(() => {
trigger.click();
fixture.detectChanges();
flush();

const option = overlayContainerElement.querySelector(
'dt-option',
) as HTMLElement;
option.click();
fixture.detectChanges();
flush();

const customTrigger = fixture.debugElement.query(
By.directive(DtSelectValueTemplate),
);

expect(customTrigger).toBeNull();
}));

it('should be defined', fakeAsync(() => {
trigger.click();
fixture.detectChanges();
flush();

fixture.componentInstance._customTemplate = true;

const option = overlayContainerElement.querySelector(
'dt-option',
) as HTMLElement;
option.click();
fixture.detectChanges();
flush();

const customTrigger = fixture.debugElement.query(
By.directive(DtSelectValueTemplate),
);

expect(customTrigger).toBeDefined();
}));
});

describe('overlay panel', () => {
let fixture: ComponentFixture<BasicSelect>;
let trigger: HTMLElement;
Expand Down Expand Up @@ -2495,3 +2548,30 @@ class ResetValuesSelect {
class SelectWithOptionValueZero {
@ViewChild(DtSelect) select: DtSelect<any>;
}

@Component({
template: `
<dt-form-field>
<dt-select placeholder="Service" [formControl]="control">
<dt-select-value-template *ngIf="_customTemplate">
<dt-icon [name]="control.value?.value"></dt-icon>
</dt-select-value-template>
<dt-option *ngFor="let service of services" [value]="service">
{{ service.viewValue }}
</dt-option>
<dt-option>None</dt-option>
</dt-select>
</dt-form-field>
`,
})
class SelectWithCustomTrigger {
services: any[] = [
{ value: 'cloud-spanner', viewValue: 'Cloud Spanner' },
{ value: 'cloud-sql', viewValue: 'Cloud SQL' },
{ value: 'cloud-storage', viewValue: 'Cloud Storage' },
];
control = new FormControl();
_customTemplate: boolean = false;

@ViewChild(DtSelect) select: DtSelect<any>;
}
6 changes: 6 additions & 0 deletions libs/barista-components/select/src/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ContentChild,
ContentChildren,
DoCheck,
ElementRef,
Expand Down Expand Up @@ -103,6 +104,7 @@ import {
DtFormField,
DtFormFieldControl,
} from '@dynatrace/barista-components/form-field';
import { DtSelectValueTemplate } from './select-value-template';

let uniqueId = 0;

Expand Down Expand Up @@ -438,6 +440,10 @@ export class DtSelect<T>
@ViewChild(CdkConnectedOverlay)
overlayDir: CdkConnectedOverlay;

/** @internal Custom trigger template. */
@ContentChild(DtSelectValueTemplate)
_customValueTemplate: DtSelectValueTemplate;

/** All of the defined select options. */
@ContentChildren(DtOption, { descendants: true }) options: QueryList<
DtOption<T>
Expand Down
3 changes: 3 additions & 0 deletions libs/examples/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ import { DtExampleSecondaryNavMulti } from './secondary-nav/secondary-nav-multi-
import { DtExampleSecondaryNavRouterLinkActive } from './secondary-nav/secondary-nav-router-link-active-example/secondary-nav-router-link-active-example';
import { DtExampleSecondaryNavTitle } from './secondary-nav/secondary-nav-title-example/secondary-nav-title-example';
import { DtExampleSelectComplexValue } from './select/select-complex-value-example/select-complex-value-example';
import { DtExampleSelectCustomValueTemplate } from './select/select-custom-value-template-example/select-custom-value-template-example';
import { DtExampleSelectDefault } from './select/select-default-example/select-default-example';
import { DtExampleSelectDisabled } from './select/select-disabled-example/select-disabled-example';
import { DtExampleSelectFormField } from './select/select-form-field-example/select-form-field-example';
Expand Down Expand Up @@ -704,6 +705,7 @@ export {
DtExampleTreeTableProblemIndicator,
DtExampleTreeTableSimple,
DtExampleFilterFieldInfiniteDataDepth,
DtExampleSelectCustomValueTemplate,
};

export const EXAMPLES_MAP = new Map<string, Type<unknown>>([
Expand Down Expand Up @@ -989,6 +991,7 @@ export const EXAMPLES_MAP = new Map<string, Type<unknown>>([
['DtExampleSelectGroups', DtExampleSelectGroups],
['DtExampleSelectValue', DtExampleSelectValue],
['DtExampleSelectWithIcons', DtExampleSelectWithIcons],
['DtExampleSelectCustomValueTemplate', DtExampleSelectCustomValueTemplate],
['DtExampleShowMoreDark', DtExampleShowMoreDark],
['DtExampleShowMoreDefault', DtExampleShowMoreDefault],
['DtExampleShowMoreDisabled', DtExampleShowMoreDisabled],
Expand Down
1 change: 1 addition & 0 deletions libs/examples/src/select/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ export * from './select-forms-example/select-forms-example';
export * from './select-groups-example/select-groups-example';
export * from './select-value-example/select-value-example';
export * from './select-with-icons-example/select-with-icons-example';
export * from './select-custom-value-template-example/select-custom-value-template-example';
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<dt-select
placeholder="Choose your color"
[(ngModel)]="selectedValue"
aria-label="Choose your color"
>
<dt-select-value-template>
<span [style.background]="selectedValue?.value"></span>
</dt-select-value-template>
<dt-option *ngFor="let color of colors" [value]="color">
<div>
<span [style.background]="color.value"></span>
{{ color.viewValue }}
</div>
</dt-option>
</dt-select>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @license
* Copyright 2020 Dynatrace LLC
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Component } from '@angular/core';

@Component({
selector: 'dt-example-select-custom-value-template-example',
templateUrl: './select-custom-value-template-example.html',
styles: [
'dt-option div, ::ng-deep .dt-select-trigger .dt-select-value { display: flex; align-items: center; }',
'.dt-select-value-template span, dt-option span { display: flex; height: 15px; width: 15px; margin-right: 5px; border-radius: 2px; }',
],
})
export class DtExampleSelectCustomValueTemplate {
selectedValue: { value: string; viewValue: string };
colors = [
{ viewValue: 'Red', value: 'red' },
{ viewValue: 'Blue', value: 'blue' },
{ viewValue: 'Green', value: 'green' },
];
}
2 changes: 2 additions & 0 deletions libs/examples/src/select/select-examples.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { DtIconModule } from '@dynatrace/barista-components/icon';
import { DtFormFieldModule } from '@dynatrace/barista-components/form-field';
import { DtCheckboxModule } from '@dynatrace/barista-components/checkbox';
import { DtExampleSelectComplexValue } from './select-complex-value-example/select-complex-value-example';
import { DtExampleSelectCustomValueTemplate } from './select-custom-value-template-example/select-custom-value-template-example';
import { DtExampleSelectDefault } from './select-default-example/select-default-example';
import { DtExampleSelectDisabled } from './select-disabled-example/select-disabled-example';
import { DtExampleSelectFormField } from './select-form-field-example/select-form-field-example';
Expand Down Expand Up @@ -49,6 +50,7 @@ import { DtExampleSelectValue } from './select-value-example/select-value-exampl
DtExampleSelectGroups,
DtExampleSelectValue,
DtExampleSelectWithIcons,
DtExampleSelectCustomValueTemplate,
],
})
export class DtExamplesSelectModule {}

0 comments on commit 7621940

Please sign in to comment.