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

Commit a748eba

Browse files
author
Yvonne Yip
committed
validate input using html constraints api
1 parent 82c419e commit a748eba

File tree

2 files changed

+182
-127
lines changed

2 files changed

+182
-127
lines changed

core-input.html

+138-101
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,37 @@
1818
*
1919
* <core-input multiline placeholder="Enter multiple lines here"></core-input>
2020
*
21-
* The text input's value is considered "committed" if the user hits the `enter`
22-
* key or blurs the input after changing the value. The "change" event is fired
21+
* The text input's value is considered "committed" if the user hits the "enter"
22+
* key or blurs the input after changing the value. The `change` event is fired
2323
* when the value becomes committed, and the committed value is stored in the
24-
* "value" property. The current value of the input is stored in the "inputValue"
24+
* `value` property. The current value of the input is stored in the `inputValue`
2525
* property.
2626
*
27-
* core-input also can optionally validate the value by providing it with a
28-
* regular expression to match against, or a validation function. The
29-
* "input-invalid" event is fired if the input value changes and is invalid.
30-
* The "invalid" property is also available for observation.
27+
* Validation
28+
* ----------
29+
*
30+
* core-input can optionally validate the value using the HTML5 constraints API,
31+
* similar to native inputs. There are two methods to enable input validation:
32+
*
33+
* 1. By setting the `type` attribute. For example, setting it to `email` will
34+
* check the value is a valid email, and setting it to `number` will check
35+
* the input is a number.
36+
*
37+
* 2. By setting attributes related to validation. The attributes are `pattern`,
38+
* `min`, `max`, `step` and `required`.
39+
*
40+
* Only `required` is supported for multiline inputs currently.
3141
*
3242
* Example:
3343
*
34-
* // valid only if the value is a number
35-
* <core-input validate="^[0-9]*$" on-input-invalid="{{inputInvalidAction}}"></core-input>
44+
* <core-input type="email" placeholder="enter your email"></core-input>
45+
*
46+
* <core-input type="number" min="5" placeholder="enter a number greater than or equal to 5"></core-input>
3647
*
37-
* this.$.input.validate = /^[0-9]*$/; // valid only if the value is a number
48+
* <core-input pattern=".*abc.*" placeholder="enter something containing 'abc'"></core-input>
3849
*
39-
* this.$.input2.validate = function(value) {
40-
* return value === 'foo'; // valid only if the value is 'foo'
41-
* }
50+
* See https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation
51+
* for more info on validation.
4252
*
4353
* @group Polymer Core Elements
4454
* @element core-input
@@ -89,7 +99,7 @@
8999
</template>
90100

91101
<template if="{{!multiline}}">
92-
<input id="input" value="{{inputValue}}" disabled?="{{disabled}}" type="{{type}}" placeholder="{{placeholder}}" required?="{{required}}" readonly?="{{readonly}}" aria-label="{{label || placeholder}}" aria-invalid="{{invalid}}" on-change="{{inputChangeAction}}" on-focus="{{inputFocusAction}}" on-blur="{{inputBlurAction}}">
102+
<input id="input" value="{{inputValue}}" disabled?="{{disabled}}" type="{{type}}" placeholder="{{placeholder}}" required?="{{required}}" readonly?="{{readonly}}" pattern="{{pattern}}" min="{{min}}" max="{{max}}" step="{{step}}" maxlength="{{maxlength}}" aria-label="{{label || placeholder}}" aria-invalid="{{invalid}}" on-keydown="{{keydownAction}}" on-change="{{inputChangeAction}}" on-focus="{{inputFocusAction}}" on-blur="{{inputBlurAction}}">
93103
</template>
94104

95105
</template>
@@ -118,15 +128,6 @@
118128
*/
119129
disabled: false,
120130

121-
/**
122-
* Set the input type. Not supported for `multiline`.
123-
*
124-
* @attribute type
125-
* @type string
126-
* @default text
127-
*/
128-
type: 'text',
129-
130131
/**
131132
* If true, the user cannot modify the value of the input.
132133
*
@@ -136,15 +137,6 @@
136137
*/
137138
readonly: false,
138139

139-
/**
140-
* If true, the input is invalid until the value becomes non-null.
141-
*
142-
* @attribute required
143-
* @type boolean
144-
* @default false
145-
*/
146-
required: false,
147-
148140
/**
149141
* If true, this input accepts multi-line input like a `<textarea>`
150142
*
@@ -187,36 +179,73 @@
187179
* @default ''
188180
*/
189181
value: '',
190-
182+
183+
/**
184+
* Set the input type. Not supported for `multiline`.
185+
*
186+
* @attribute type
187+
* @type string
188+
* @default text
189+
*/
190+
type: 'text',
191+
192+
/**
193+
* If true, the input is invalid if its value is null.
194+
*
195+
* @attribute required
196+
* @type boolean
197+
* @default false
198+
*/
199+
required: false,
200+
191201
/**
192-
* If this property is not null, the text input's inputValue will be
193-
* validated. You can validate the value with either a regular expression
194-
* or a custom function.
202+
* A regular expression to validate the input value against. See
203+
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
204+
* for more info. Not supported if `multiline` is true.
195205
*
196-
* To use a regular expression, set this property to a RegExp object or
197-
* a string containing the regular expression to match against. To use a
198-
* custom validator, set this property to a function with the signature
199-
* function(value) that returns a boolean. The input is valid if the
200-
* function returns true.
206+
* @attribute pattern
207+
* @type string
208+
* @default '.*'
209+
*/
210+
// FIXME(yvonne): The default is set to .* because we can't bind to pattern such
211+
// that the attribute is unset if pattern is null.
212+
pattern: '.*',
213+
214+
/**
215+
* If set, the input is invalid if the value is less than this property. See
216+
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
217+
* for more info. Not supported if `multiline` is true.
201218
*
202-
* Example:
219+
* @attribute min
220+
*/
221+
min: null,
222+
223+
/**
224+
* If set, the input is invalid if the value is greater than this property. See
225+
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
226+
* for more info. Not supported if `multiline` is true.
203227
*
204-
* // valid only if the value is a number
205-
* <core-input validate="^[0-9]*$"></core-input>
206-
*
207-
* // valid only if the value is a number
208-
* this.$.input.validate = /^[0-9]*$/;
228+
* @attribute max
229+
*/
230+
max: null,
231+
232+
/**
233+
* If set, the input is invalid if the value is not `min` plus an integral multiple
234+
* of this property. See
235+
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
236+
* for more info. Not supported if `multiline` is true.
209237
*
210-
* this.$.input2.validate = function(value) {
211-
* // valid only if the value is 'foo'
212-
* return value === 'foo';
213-
* }
238+
* @attribute step
239+
*/
240+
step: null,
241+
242+
/**
243+
* The maximum length of the input value.
214244
*
215-
* @attribute validate
216-
* @type string|RegExp|Function(value)
217-
* @default null
245+
* @attribute maxlength
246+
* @type number
218247
*/
219-
validate: null,
248+
maxlength: null,
220249

221250
/**
222251
* If this property is true, the text input's inputValue failed validation.
@@ -225,52 +254,28 @@
225254
* @type boolean
226255
* @default false
227256
*/
228-
invalid: false,
257+
invalid: false
229258
},
230259

231260
ready: function() {
232261
this.handleTabindex(this.getAttribute('tabindex'));
233262
},
234263

235-
validateValue: function() {
236-
var valid = true;
237-
238-
if (this.validate) {
239-
240-
if (!this.inputValue) {
241-
valid = !this.required;
242-
} else if (typeof this.validate === 'string') {
243-
valid = new RegExp(this.validate).exec(this.inputValue);
244-
} else if (this.validate.exec) {
245-
valid = this.validate.exec(this.inputValue);
246-
} else if (this.validate instanceof Function) {
247-
valid = this.validate.call(this, this.inputValue);
248-
}
249-
250-
} else if (this.required) {
251-
valid = !!this.inputValue;
252-
}
253-
254-
this.invalid = !valid;
255-
},
256-
257264
invalidChanged: function() {
258265
this.classList.toggle('invalid', this.invalid);
259-
this.fire('input-'+ this.invalid ? 'invalid' : 'valid', {value: this.inputValue});
266+
this.fire('input-'+ (this.invalid ? 'invalid' : 'valid'), {value: this.inputValue});
260267
},
261268

262269
inputValueChanged: function() {
263-
if (this.validate || this.required) {
264-
this.validateValue();
265-
}
270+
this.updateValidity_();
266271
},
267272

268273
valueChanged: function() {
269274
this.inputValue = this.value;
270275
},
271276

272277
requiredChanged: function() {
273-
this.validateValue();
278+
this.updateValidity_();
274279
},
275280

276281
attributeChanged: function(attr, oldVal, curVal) {
@@ -296,6 +301,22 @@
296301
this.value = this.inputValue;
297302
},
298303

304+
updateValidity_: function() {
305+
if (this.$.input.willValidate) {
306+
this.invalid = !this.$.input.validity.valid;
307+
}
308+
},
309+
310+
keydownAction: function() {
311+
// for type = number, the value is the empty string unless the input is a valid number.
312+
// FIXME(yvonne): check other types
313+
if (this.type === 'number') {
314+
this.async(function() {
315+
this.updateValidity_();
316+
});
317+
}
318+
},
319+
299320
inputChangeAction: function() {
300321
this.commit();
301322
if (!window.ShadowDOMPolyfill) {
@@ -347,40 +368,56 @@
347368
this.$.input.focus();
348369
},
349370

350-
setSelectionRange: function( selectionStart, selectionEnd, selectionDirection ) {
371+
setSelectionRange: function(selectionStart, selectionEnd, selectionDirection) {
351372
// forward setSelectionRange method to the internal input / textarea element
352-
this.$.input.setSelectionRange( selectionStart, selectionEnd, selectionDirection );
373+
this.$.input.setSelectionRange(selectionStart, selectionEnd, selectionDirection);
353374
},
354375

355-
setRangeText: function( replacement, start, end, selectMode ) {
376+
setRangeText: function(replacement, start, end, selectMode) {
356377
// forward setRangeText method to the internal input element
357-
if ( !this.multiline ) {
358-
this.$.input.setRangeText( replacement, start, end, selectMode );
378+
if (!this.multiline) {
379+
this.$.input.setRangeText(replacement, start, end, selectMode);
359380
}
360381
},
361382

362-
stepDown: function( n ) {
383+
stepDown: function(n) {
363384
// forward stepDown method to the internal input element
364-
if ( !this.multiline ) {
365-
this.$.input.stepDown( n );
385+
if (!this.multiline) {
386+
this.$.input.stepDown(n);
366387
}
367388
},
368389

369-
stepUp: function( n ) {
390+
stepUp: function(n) {
370391
// forward stepUp method to the internal input element
371-
if ( !this.multiline ) {
372-
this.$.input.stepUp( n );
392+
if (!this.multiline) {
393+
this.$.input.stepUp(n);
373394
}
395+
},
396+
397+
get willValidate() {
398+
return this.$.input.willValidate;
399+
},
400+
401+
get validity() {
402+
return this.$.input.validity;
403+
},
404+
405+
get validationMessage() {
406+
return this.$.input.validationMessage;
407+
},
408+
409+
checkValidity: function() {
410+
var r = this.$.input.checkValidity();
411+
this.updateValidity_();
412+
return r;
413+
},
414+
415+
setCustomValidity: function(message) {
416+
this.$.input.setCustomValidity(message);
417+
this.updateValidity_();
374418
}
375419

376420
});
377-
378-
CoreInput = function() {
379-
return document.createElement('core-input');
380-
};
381-
CoreInput.validate = {
382-
number: /^[0-9]*$/
383-
};
384421
</script>
385422

386423
</polymer-element>

0 commit comments

Comments
 (0)