Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.

Commit cb17052

Browse files
Teoxoylynnmercier
authored andcommitted
feat(textfield): Add valid setter, so clients can set custom validity
Resolves #1018
1 parent cdd367e commit cb17052

File tree

5 files changed

+68
-9
lines changed

5 files changed

+68
-9
lines changed

packages/mdc-textfield/README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,9 @@ by HTML5's form validation API.
153153
</div>
154154
```
155155

156-
An input's validity is checked via `checkValidity()` on blur, and the styles are updated
157-
accordingly. When using the `required` attribute, an asterisk will be automatically appended to the
158-
label text, as per the spec.
156+
By default an input's validity is checked via `checkValidity()` on blur, and the styles are updated
157+
accordingly. Set the MDCTextfield.valid variable to set the input's validity explicitly. MDC Textfield
158+
automatically appends an asterisk to the label text if the required attribute is set.
159159

160160
Help text can be used to provide additional validation messages. Use
161161
`mdc-textfield-helptext--validation-msg` to provide styles for using the help text as a validation
@@ -324,6 +324,10 @@ with the corresponding id within the document and automatically assign it to thi
324324
Boolean. Proxies to the foundation's `isDisabled/setDisabled` methods when retrieved/set
325325
respectively.
326326

327+
##### MDCTextfield.valid
328+
329+
Boolean setter. Proxies to the foundation's `setValid` method when set.
330+
327331
##### MDCTextfield.ripple
328332

329333
`MDCRipple` instance. Set to the `MDCRipple` instance for the root element that `MDCTextfield`

packages/mdc-textfield/foundation.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export default class MDCTextfieldFoundation extends MDCFoundation {
5757
this.inputBlurHandler_ = () => this.deactivateFocus_();
5858
this.inputInputHandler_ = () => this.autoCompleteFocus_();
5959
this.inputKeydownHandler_ = () => this.receivedUserInput_ = true;
60+
this.useCustomValidityChecking_ = false;
6061
}
6162

6263
init() {
@@ -99,24 +100,30 @@ export default class MDCTextfieldFoundation extends MDCFoundation {
99100
}
100101

101102
deactivateFocus_() {
102-
const {FOCUSED, INVALID, LABEL_FLOAT_ABOVE} = MDCTextfieldFoundation.cssClasses;
103+
const {FOCUSED, LABEL_FLOAT_ABOVE} = MDCTextfieldFoundation.cssClasses;
103104
const input = this.getNativeInput_();
104-
const isValid = input.checkValidity();
105105

106106
this.adapter_.removeClass(FOCUSED);
107107
if (!input.value && !this.isBadInput_()) {
108108
this.adapter_.removeClassFromLabel(LABEL_FLOAT_ABOVE);
109109
this.receivedUserInput_ = false;
110110
}
111+
if (!this.useCustomValidityChecking_) {
112+
this.changeValidity_(input.checkValidity());
113+
}
114+
}
115+
116+
changeValidity_(isValid) {
117+
const {INVALID} = MDCTextfieldFoundation.cssClasses;
111118
if (isValid) {
112119
this.adapter_.removeClass(INVALID);
113120
} else {
114121
this.adapter_.addClass(INVALID);
115122
}
116-
this.updateHelptextOnDeactivation_(isValid);
123+
this.updateHelptext_(isValid);
117124
}
118125

119-
updateHelptextOnDeactivation_(isValid) {
126+
updateHelptext_(isValid) {
120127
const {HELPTEXT_PERSISTENT, HELPTEXT_VALIDATION_MSG} = MDCTextfieldFoundation.cssClasses;
121128
const {ROLE} = MDCTextfieldFoundation.strings;
122129
const helptextIsPersistent = this.adapter_.helptextHasClass(HELPTEXT_PERSISTENT);
@@ -167,4 +174,9 @@ export default class MDCTextfieldFoundation extends MDCFoundation {
167174
badInput: false,
168175
};
169176
}
177+
178+
setValid(isValid) {
179+
this.useCustomValidityChecking_ = true;
180+
this.changeValidity_(isValid);
181+
}
170182
}

packages/mdc-textfield/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ export class MDCTextfield extends MDCComponent {
5959
this.foundation_.setDisabled(disabled);
6060
}
6161

62+
set valid(valid) {
63+
this.foundation_.setValid(valid);
64+
}
65+
6266
getDefaultFoundation() {
6367
return new MDCTextfieldFoundation(Object.assign({
6468
addClass: (className) => this.root_.classList.add(className),

test/unit/mdc-textfield/foundation.test.js

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ test('#setDisabled removes mdc-textfield--disabled when set to false', () => {
9292
td.verify(mockAdapter.removeClass(cssClasses.DISABLED));
9393
});
9494

95+
test('#setValid adds mdc-textfied--invalid when set to false', () => {
96+
const {foundation, mockAdapter} = setupTest();
97+
foundation.setValid(false);
98+
td.verify(mockAdapter.addClass(cssClasses.INVALID));
99+
});
100+
101+
test('#setValid removes mdc-textfied--invalid when set to true', () => {
102+
const {foundation, mockAdapter} = setupTest();
103+
foundation.setValid(true);
104+
td.verify(mockAdapter.removeClass(cssClasses.INVALID));
105+
});
106+
95107
test('#init adds mdc-textfield--upgraded class', () => {
96108
const {foundation, mockAdapter} = setupTest();
97109
foundation.init();
@@ -246,19 +258,38 @@ test('on blur does not remove mdc-textfield__label--float-above if input has a v
246258
td.verify(mockAdapter.removeClassFromLabel(cssClasses.LABEL_FLOAT_ABOVE), {times: 0});
247259
});
248260

249-
test('on blur removes mdc-textfield--invalid if input.checkValidity() returns true', () => {
261+
test('on blur removes mdc-textfield--invalid if custom validity is false and' +
262+
'input.checkValidity() returns true', () => {
250263
const {mockAdapter, blur} = setupBlurTest();
251264
blur();
252265
td.verify(mockAdapter.removeClass(cssClasses.INVALID));
253266
});
254267

255-
test('on blur adds mdc-textfied--invalid if input.checkValidity() returns false', () => {
268+
test('on blur adds mdc-textfied--invalid if custom validity is false and' +
269+
'input.checkValidity() returns false', () => {
256270
const {mockAdapter, blur, nativeInput} = setupBlurTest();
257271
nativeInput.checkValidity = () => false;
258272
blur();
259273
td.verify(mockAdapter.addClass(cssClasses.INVALID));
260274
});
261275

276+
test('on blur does not remove mdc-textfield--invalid if custom validity is true and' +
277+
'input.checkValidity() returns true', () => {
278+
const {foundation, mockAdapter, blur} = setupBlurTest();
279+
foundation.setValid(false);
280+
blur();
281+
td.verify(mockAdapter.removeClass(cssClasses.INVALID), {times: 0});
282+
});
283+
284+
test('on blur does not add mdc-textfied--invalid if custom validity is true and' +
285+
'input.checkValidity() returns false', () => {
286+
const {foundation, mockAdapter, blur, nativeInput} = setupBlurTest();
287+
nativeInput.checkValidity = () => false;
288+
foundation.setValid(true);
289+
blur();
290+
td.verify(mockAdapter.addClass(cssClasses.INVALID), {times: 0});
291+
});
292+
262293
test('on blur adds role="alert" to helptext if input is invalid and helptext is being used ' +
263294
'as a validation message', () => {
264295
const {mockAdapter, blur, nativeInput} = setupBlurTest();

test/unit/mdc-textfield/mdc-textfield.test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ test('get/set disabled updates the component styles', () => {
119119
assert.isNotOk(root.classList.contains(cssClasses.DISABLED));
120120
});
121121

122+
test('set valid updates the component styles', () => {
123+
const {root, component} = setupTest();
124+
component.valid = false;
125+
assert.isOk(root.classList.contains(cssClasses.INVALID));
126+
component.valid = true;
127+
assert.isNotOk(root.classList.contains(cssClasses.INVALID));
128+
});
129+
122130
test('#adapter.addClass adds a class to the root element', () => {
123131
const {root, component} = setupTest();
124132
component.getDefaultFoundation().adapter_.addClass('foo');

0 commit comments

Comments
 (0)