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

Commit

Permalink
validate input using html constraints api
Browse files Browse the repository at this point in the history
  • Loading branch information
Yvonne Yip committed Jul 24, 2014
1 parent 82c419e commit a748eba
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 127 deletions.
239 changes: 138 additions & 101 deletions core-input.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,37 @@
*
* <core-input multiline placeholder="Enter multiple lines here"></core-input>
*
* The text input's value is considered "committed" if the user hits the `enter`
* key or blurs the input after changing the value. The "change" event is fired
* The text input's value is considered "committed" if the user hits the "enter"
* key or blurs the input after changing the value. The `change` event is fired
* when the value becomes committed, and the committed value is stored in the
* "value" property. The current value of the input is stored in the "inputValue"
* `value` property. The current value of the input is stored in the `inputValue`
* property.
*
* core-input also can optionally validate the value by providing it with a
* regular expression to match against, or a validation function. The
* "input-invalid" event is fired if the input value changes and is invalid.
* The "invalid" property is also available for observation.
* Validation
* ----------
*
* core-input can optionally validate the value using the HTML5 constraints API,
* similar to native inputs. There are two methods to enable input validation:
*
* 1. By setting the `type` attribute. For example, setting it to `email` will
* check the value is a valid email, and setting it to `number` will check
* the input is a number.
*
* 2. By setting attributes related to validation. The attributes are `pattern`,
* `min`, `max`, `step` and `required`.
*
* Only `required` is supported for multiline inputs currently.
*
* Example:
*
* // valid only if the value is a number
* <core-input validate="^[0-9]*$" on-input-invalid="{{inputInvalidAction}}"></core-input>
* <core-input type="email" placeholder="enter your email"></core-input>
*
* <core-input type="number" min="5" placeholder="enter a number greater than or equal to 5"></core-input>
*
* this.$.input.validate = /^[0-9]*$/; // valid only if the value is a number
* <core-input pattern=".*abc.*" placeholder="enter something containing 'abc'"></core-input>
*
* this.$.input2.validate = function(value) {
* return value === 'foo'; // valid only if the value is 'foo'
* }
* See https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation
* for more info on validation.
*
* @group Polymer Core Elements
* @element core-input
Expand Down Expand Up @@ -89,7 +99,7 @@
</template>

<template if="{{!multiline}}">
<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}}">
<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}}">
</template>

</template>
Expand Down Expand Up @@ -118,15 +128,6 @@
*/
disabled: false,

/**
* Set the input type. Not supported for `multiline`.
*
* @attribute type
* @type string
* @default text
*/
type: 'text',

/**
* If true, the user cannot modify the value of the input.
*
Expand All @@ -136,15 +137,6 @@
*/
readonly: false,

/**
* If true, the input is invalid until the value becomes non-null.
*
* @attribute required
* @type boolean
* @default false
*/
required: false,

/**
* If true, this input accepts multi-line input like a `<textarea>`
*
Expand Down Expand Up @@ -187,36 +179,73 @@
* @default ''
*/
value: '',


/**
* Set the input type. Not supported for `multiline`.
*
* @attribute type
* @type string
* @default text
*/
type: 'text',

/**
* If true, the input is invalid if its value is null.
*
* @attribute required
* @type boolean
* @default false
*/
required: false,

/**
* If this property is not null, the text input's inputValue will be
* validated. You can validate the value with either a regular expression
* or a custom function.
* A regular expression to validate the input value against. See
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
* for more info. Not supported if `multiline` is true.
*
* To use a regular expression, set this property to a RegExp object or
* a string containing the regular expression to match against. To use a
* custom validator, set this property to a function with the signature
* function(value) that returns a boolean. The input is valid if the
* function returns true.
* @attribute pattern
* @type string
* @default '.*'
*/
// FIXME(yvonne): The default is set to .* because we can't bind to pattern such
// that the attribute is unset if pattern is null.
pattern: '.*',

/**
* If set, the input is invalid if the value is less than this property. See
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
* for more info. Not supported if `multiline` is true.
*
* Example:
* @attribute min
*/
min: null,

/**
* If set, the input is invalid if the value is greater than this property. See
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
* for more info. Not supported if `multiline` is true.
*
* // valid only if the value is a number
* <core-input validate="^[0-9]*$"></core-input>
*
* // valid only if the value is a number
* this.$.input.validate = /^[0-9]*$/;
* @attribute max
*/
max: null,

/**
* If set, the input is invalid if the value is not `min` plus an integral multiple
* of this property. See
* https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes
* for more info. Not supported if `multiline` is true.
*
* this.$.input2.validate = function(value) {
* // valid only if the value is 'foo'
* return value === 'foo';
* }
* @attribute step
*/
step: null,

/**
* The maximum length of the input value.
*
* @attribute validate
* @type string|RegExp|Function(value)
* @default null
* @attribute maxlength
* @type number
*/
validate: null,
maxlength: null,

/**
* If this property is true, the text input's inputValue failed validation.
Expand All @@ -225,52 +254,28 @@
* @type boolean
* @default false
*/
invalid: false,
invalid: false
},

ready: function() {
this.handleTabindex(this.getAttribute('tabindex'));
},

validateValue: function() {
var valid = true;

if (this.validate) {

if (!this.inputValue) {
valid = !this.required;
} else if (typeof this.validate === 'string') {
valid = new RegExp(this.validate).exec(this.inputValue);
} else if (this.validate.exec) {
valid = this.validate.exec(this.inputValue);
} else if (this.validate instanceof Function) {
valid = this.validate.call(this, this.inputValue);
}

} else if (this.required) {
valid = !!this.inputValue;
}

this.invalid = !valid;
},

invalidChanged: function() {
this.classList.toggle('invalid', this.invalid);
this.fire('input-'+ this.invalid ? 'invalid' : 'valid', {value: this.inputValue});
this.fire('input-'+ (this.invalid ? 'invalid' : 'valid'), {value: this.inputValue});
},

inputValueChanged: function() {
if (this.validate || this.required) {
this.validateValue();
}
this.updateValidity_();
},

valueChanged: function() {
this.inputValue = this.value;
},

requiredChanged: function() {
this.validateValue();
this.updateValidity_();
},

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

updateValidity_: function() {
if (this.$.input.willValidate) {
this.invalid = !this.$.input.validity.valid;
}
},

keydownAction: function() {
// for type = number, the value is the empty string unless the input is a valid number.
// FIXME(yvonne): check other types
if (this.type === 'number') {
this.async(function() {
this.updateValidity_();
});
}
},

inputChangeAction: function() {
this.commit();
if (!window.ShadowDOMPolyfill) {
Expand Down Expand Up @@ -347,40 +368,56 @@
this.$.input.focus();
},

setSelectionRange: function( selectionStart, selectionEnd, selectionDirection ) {
setSelectionRange: function(selectionStart, selectionEnd, selectionDirection) {
// forward setSelectionRange method to the internal input / textarea element
this.$.input.setSelectionRange( selectionStart, selectionEnd, selectionDirection );
this.$.input.setSelectionRange(selectionStart, selectionEnd, selectionDirection);
},

setRangeText: function( replacement, start, end, selectMode ) {
setRangeText: function(replacement, start, end, selectMode) {
// forward setRangeText method to the internal input element
if ( !this.multiline ) {
this.$.input.setRangeText( replacement, start, end, selectMode );
if (!this.multiline) {
this.$.input.setRangeText(replacement, start, end, selectMode);
}
},

stepDown: function( n ) {
stepDown: function(n) {
// forward stepDown method to the internal input element
if ( !this.multiline ) {
this.$.input.stepDown( n );
if (!this.multiline) {
this.$.input.stepDown(n);
}
},

stepUp: function( n ) {
stepUp: function(n) {
// forward stepUp method to the internal input element
if ( !this.multiline ) {
this.$.input.stepUp( n );
if (!this.multiline) {
this.$.input.stepUp(n);
}
},

get willValidate() {
return this.$.input.willValidate;
},

get validity() {
return this.$.input.validity;
},

get validationMessage() {
return this.$.input.validationMessage;
},

checkValidity: function() {
var r = this.$.input.checkValidity();
this.updateValidity_();
return r;
},

setCustomValidity: function(message) {
this.$.input.setCustomValidity(message);
this.updateValidity_();
}

});

CoreInput = function() {
return document.createElement('core-input');
};
CoreInput.validate = {
number: /^[0-9]*$/
};
</script>

</polymer-element>
Loading

0 comments on commit a748eba

Please sign in to comment.