Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit 9062e3c

Browse files
authored
feat(select): Improved Helper Text (#2248)
- Remove `mdcSelectHelperText` component - Add `helper: string` to `MdcSelect` - Add `helperPersistent: boolean` to `MdcSelect` - Add `validationMessage: string` to `MdcSelect` BREAKING CHANGES: * Removed `mdcSelectHelperText` component, use `helper: string` instead * Validation messages are set using `validationMessage: string`. See examples * Helper text is set using `helper: string`. See examples * Persistent helper text is enabled using `helperPersistent: boolean`. See examples closes #2246
1 parent 7bd8c44 commit 9062e3c

File tree

9 files changed

+202
-198
lines changed

9 files changed

+202
-198
lines changed

demos/src/app/components/select/examples.html

+6-20
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ <h3 class="demo-content__headline">Select</h3>
2020
<button mdc-button (click)="standardSelect.focus()">Focus</button>
2121
</div>
2222
<mdc-select #standardSelect placeholder="Fruit" name="my-select" required
23-
[helperText]="standardSelectHelper"
23+
helper="Helper text" helperPersistent validationMessage="Field is required"
2424
(selectionChange)="onSelectionChange($event)">
2525
<mdc-menu class="demo-select-width" [anchorMargin]="{top: 10}">
2626
<mdc-list>
@@ -32,8 +32,6 @@ <h3 class="demo-content__headline">Select</h3>
3232
</mdc-list>
3333
</mdc-menu>
3434
</mdc-select>
35-
<mdc-select-helper-text #standardSelectHelper validation>Field is required
36-
</mdc-select-helper-text>
3735
<p> Value: {{ standardSelect.value }}</p>
3836
<p> Index: {{ standardSelect.getSelectedIndex() }}</p>
3937
<example-viewer [example]="exampleStandard"></example-viewer>
@@ -66,7 +64,7 @@ <h3 class="demo-content__headline">Leading Icon</h3>
6664
{{meal.disabled ? 'On' : 'Off'}}</button>
6765
<button mdc-button (click)="meal.setSelectedIndex(2)">Set Index (2)</button>
6866
</div>
69-
<mdc-select #meal [helperText]="mealHelper" required
67+
<mdc-select #meal required validationMessage="Meal selection is required"
7068
placeholder="Pick a Meal">
7169
<mdc-icon mdcSelectIcon>fastfood</mdc-icon>
7270
<mdc-menu class="demo-select-width">
@@ -78,9 +76,6 @@ <h3 class="demo-content__headline">Leading Icon</h3>
7876
</mdc-list>
7977
</mdc-menu>
8078
</mdc-select>
81-
<mdc-select-helper-text #mealHelper validation>
82-
<span *ngIf="!meal.value">Meal selection is required</span>
83-
</mdc-select-helper-text>
8479
<example-viewer [example]="exampleLeadingIcon"></example-viewer>
8580
</div>
8681

@@ -132,20 +127,15 @@ <h3 class="demo-content__headline">Custom Enhanced</h3>
132127
<div class="demo-content">
133128
<h3 class="demo-content__headline">Lazy Load</h3>
134129
<form [formGroup]="lazyLoadForm" #formDirectiveLazy="ngForm">
135-
<mdc-select outlined formControlName="lazySelect" [helperText]="lazyHelper"
136-
placeholder="Example">
130+
<mdc-select outlined formControlName="lazySelect"
131+
validationMessage="Selection is required" placeholder="Example">
137132
<mdc-menu class="demo-select-width">
138133
<mdc-list>
139134
<mdc-list-item *ngFor="let food of lazyFoods" [value]="food.value"
140135
[disabled]="food.disabled">{{food.viewValue}}</mdc-list-item>
141136
</mdc-list>
142137
</mdc-menu>
143138
</mdc-select>
144-
<mdc-select-helper-text #lazyHelper validation>
145-
<span
146-
*ngIf="lazyLoadForm.controls['lazySelect'].hasError('required')">Selection
147-
is required</span>
148-
</mdc-select-helper-text>
149139

150140
<div class="demo-layout__row">
151141
<button mdc-button (click)="loadFoods()">Load</button>
@@ -227,19 +217,15 @@ <h3 class="demo-content__headline">Select with FormControl</h3>
227217
<form [formGroup]="foodForm" id="foodForm" (ngSubmit)="submitForm()"
228218
#formDirective="ngForm">
229219
<mdc-select #favoriteFood placeholder="Favorite food"
230-
formControlName="favoriteFood" [helperText]="reactiveHelper">
220+
formControlName="favoriteFood" validationMessage="Selection is required">
231221
<mdc-menu class="demo-select-width">
232222
<mdc-list>
233223
<mdc-list-item *ngFor="let food of foods" [value]="food.value"
234224
[disabled]="food.disabled">{{food.viewValue}}</mdc-list-item>
235225
</mdc-list>
236226
</mdc-menu>
237227
</mdc-select>
238-
<mdc-select-helper-text #reactiveHelper validation>
239-
<span
240-
*ngIf="foodForm.controls['favoriteFood'].hasError('required')">Selection
241-
is required</span>
242-
</mdc-select-helper-text>
228+
243229
<div class="demo-layout__row">
244230
<button mdc-button>Submit</button>
245231
<button mdc-button type="button"

demos/src/app/components/select/select.ts

+9-38
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,10 @@ export class Api implements OnInit {
6868
{name: 'tabIndex: number', summary: `Set the underlying tab index of the select. (Default is 0)`},
6969
{name: 'outlined: boolean', summary: `Styles the select as an outlined select.`},
7070
{name: 'disabled: boolean', summary: `Enables/disables the select.`},
71-
{name: 'helperText: MdcHelperText', summary: `Reference to related MdcHelperText`},
7271
{name: 'compareWith: (o1: any, o2: any) => boolean', summary: `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.`},
72+
{name: 'helper: string', summary: `Helper text to display below the input when focused.`},
73+
{name: 'helperPersistent: boolean', summary: 'Always show the helper text despite focus.'},
74+
{name: 'validationMessage: string', summary: 'Message to show in the error color when the select is invalid. (Helper text will not be visible)'},
7375
]
7476
},
7577
{
@@ -91,30 +93,6 @@ export class Api implements OnInit {
9193
},
9294
]
9395
},
94-
{
95-
header: 'MDCSelectHelperText',
96-
selectors: [
97-
'mdc-select-helper-text',
98-
'mdcSelectHelperText'
99-
],
100-
exportedAs: 'mdcSelectHelperText',
101-
categories: [
102-
{
103-
name: 'Properties',
104-
items: [
105-
{name: 'validation: boolean', summary: `Help text can be used to provide additional validation messages.`},
106-
{name: 'persistent: boolean', summary: `Help text will always be visible.`},
107-
]
108-
},
109-
{
110-
name: 'Methods',
111-
items: [
112-
{name: 'showToScreenReader()', summary: `Makes the helper text visible to the screen reader.`},
113-
{name: 'setValidity(inputIsValid: boolean)', summary: `Sets the validity of the helper text.`},
114-
]
115-
},
116-
]
117-
},
11896
{
11997
header: 'MDC_SELECT_DEFAULT_OPTIONS',
12098
summary: `Injection token that can be used to configure the default options for all select's within an app.`,
@@ -208,7 +186,7 @@ export class Examples {
208186

209187
exampleStandard = {
210188
html: `<mdc-select #standardSelect placeholder="Fruit" name="my-select" required
211-
[helperText]="standardSelectHelper"
189+
helper="Helper text" helperPersistent validationMessage="Field is required"
212190
(selectionChange)="onSelectionChange($event)">
213191
<mdc-menu class="demo-select-width" [anchorMargin]="{top: 10}">
214192
<mdc-list>
@@ -219,9 +197,7 @@ export class Examples {
219197
<mdc-list-item disabled value="mango">Mango</mdc-list-item>
220198
</mdc-list>
221199
</mdc-menu>
222-
</mdc-select>
223-
<mdc-select-helper-text #standardSelectHelper validation>Field is required
224-
</mdc-select-helper-text>`,
200+
</mdc-select>`,
225201
sass: `https://raw.githubusercontent.com/trimox/angular-mdc-web/master/demos/src/styles/_select.scss`
226202
};
227203

@@ -274,7 +250,7 @@ export class Examples {
274250
};
275251

276252
exampleLeadingIcon = {
277-
html: `<mdc-select #meal [helperText]="mealHelper" required placeholder="Pick a Meal">
253+
html: `<mdc-select #meal validationMessage="Meal selection is required" required placeholder="Pick a Meal">
278254
<mdc-icon mdcSelectIcon>fastfood</mdc-icon>
279255
<mdc-menu>
280256
<mdc-list>
@@ -284,10 +260,7 @@ export class Examples {
284260
</mdc-list-item>
285261
</mdc-list>
286262
</mdc-menu>
287-
</mdc-select>
288-
<mdc-select-helper-text #mealHelper validation>
289-
<span *ngIf="!meal.value">Meal selection is required</span>
290-
</mdc-select-helper-text>`,
263+
</mdc-select>`,
291264
ts: `foods = [
292265
{ value: '', disabled: false },
293266
{ value: 'steak-0', viewValue: 'Steak' },
@@ -325,7 +298,8 @@ onSelectionChange(event: { index: any, value: any }) {
325298

326299
exampleReactive = {
327300
html: `<form [formGroup]="foodForm" id="foodForm" (ngSubmit)="submitForm()" #formDirective="ngForm">
328-
<mdc-select #favoriteFood placeholder="Favorite food" formControlName="favoriteFood" [helperText]="reactiveHelper">
301+
<mdc-select #favoriteFood placeholder="Favorite food" formControlName="favoriteFood"
302+
validationMessage="Selection is required">
329303
<mdc-menu>
330304
<mdc-list>
331305
<mdc-list-item *ngFor="let food of foods" [value]="food.value"
@@ -335,9 +309,6 @@ onSelectionChange(event: { index: any, value: any }) {
335309
</mdc-list>
336310
</mdc-menu>
337311
</mdc-select>
338-
<mdc-select-helper-text #reactiveHelper validation>
339-
<span *ngIf="foodForm.controls['favoriteFood'].hasError('required')">Selection is required</span>
340-
</mdc-select-helper-text>
341312
342313
<button mdc-button>Submit</button>
343314
<button mdc-button type="button" (click)="resetForm(formDirective)">Reset</button>

packages/select/helper-text.ts

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import {
2+
ElementRef,
3+
OnDestroy,
4+
} from '@angular/core';
5+
import {
6+
MDCSelectHelperTextFoundation,
7+
MDCSelectHelperTextAdapter
8+
} from '@material/select';
9+
import {MDCComponent} from '@angular-mdc/web/base';
10+
11+
export class MdcSelectHelperTextFoundation extends MDCComponent<MDCSelectHelperTextFoundation>
12+
implements OnDestroy {
13+
private _initialized: boolean = false;
14+
15+
_helperLineElement?: HTMLElement;
16+
17+
get foundation(): MDCSelectHelperTextFoundation {
18+
return this._foundation;
19+
}
20+
21+
constructor(
22+
public _hostElement: ElementRef<HTMLElement>,
23+
private _document: Document) {
24+
super(_hostElement);
25+
}
26+
27+
getDefaultFoundation() {
28+
const adapter: MDCSelectHelperTextAdapter = {
29+
addClass: (className: string) => this._helperLineElement!.classList.add(className),
30+
removeClass: (className: string) => this._helperLineElement!.classList.remove(className),
31+
hasClass: (className: string) => this._helperLineElement!.classList.contains(className),
32+
setAttr: (attr: string, value: string) => this._helperLineElement!.setAttribute(attr, value),
33+
removeAttr: (attr: string) => this._helperLineElement!.removeAttribute(attr),
34+
setContent: (content: string) => this._helperLineElement!.textContent = content,
35+
};
36+
return new MDCSelectHelperTextFoundation(adapter);
37+
}
38+
39+
/** Sets the persistency of the helper text. */
40+
setPersistent(isPersistent: boolean) {
41+
this._foundation.setPersistent(isPersistent);
42+
}
43+
44+
/** True to make the helper text act as an error validation message. */
45+
setValidation(isValidation: boolean) {
46+
this._foundation.setValidation(isValidation);
47+
}
48+
49+
/** Sets the validity of the helper text based on inputIsValid. */
50+
setValidity(inputIsValid: boolean): void {
51+
this._foundation.setValidity(inputIsValid);
52+
}
53+
54+
/** Makes the helper text visible to the screen reader. */
55+
showToScreenReader(): void {
56+
this._foundation.showToScreenReader();
57+
}
58+
59+
/** Sets the content of the helper text. */
60+
setContent(content: string) {
61+
this._foundation.setContent(content);
62+
}
63+
64+
/** Initializes the foundation. */
65+
init() {
66+
if (this._initialized) {
67+
return;
68+
}
69+
70+
this._createHelperElement();
71+
this._foundation.init();
72+
this._initialized = true;
73+
}
74+
75+
/** Destroys the foundation. */
76+
destroy() {
77+
this._helperLineElement?.parentNode?.removeChild(this._helperLineElement);
78+
this._hostElement = this._helperLineElement = null!;
79+
this._foundation.destroy();
80+
this._initialized = false;
81+
}
82+
83+
/** Creates and appends the helper element. */
84+
private _createHelperElement() {
85+
this._helperLineElement = this._document.createElement('p');
86+
this._helperLineElement.className = 'mdc-select-helper-text';
87+
this._appendHelperElement();
88+
}
89+
90+
/**
91+
* Appends the helper element to the select.
92+
*/
93+
private _appendHelperElement() {
94+
if (!this._helperLineElement) {
95+
throw Error('Helper element has not been created and cannot be appended');
96+
}
97+
98+
this._hostElement.nativeElement.insertAdjacentElement('afterend', this._helperLineElement);
99+
}
100+
101+
ngOnDestroy(): void {
102+
this.destroy();
103+
}
104+
}

packages/select/module.ts

-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ import {MdcListModule} from '@angular-mdc/web/list';
1010

1111
import {MdcSelect} from './select';
1212
import {MdcSelectIcon} from './select-icon';
13-
import {MDCSelectHelperText} from './select-helper-text';
1413

1514
const SELECT_DECLARATIONS = [
1615
MdcSelect,
17-
MDCSelectHelperText,
1816
MdcSelectIcon,
1917
];
2018

packages/select/public-api.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
export * from './module';
22
export * from './select-icon';
3-
export * from './select-helper-text';
43
export * from './select';

packages/select/select-helper-text.ts

-78
This file was deleted.

0 commit comments

Comments
 (0)