react-form-validate
Version:
A React form validator. Has the same API as jQuery.validator
239 lines (235 loc) • 8.58 kB
JSX
/**
* Created by wujianbo on 15/12/8.
*/
/**
* Usage: Set the ref of the form to be validated as :
* ref="vForm"
* then pass down the props:
* rules
* messages
* And you are all set to go!
* [CAUTION]: You will need to pass the [submit event handler] from the original Form to this ValidateableForm!
*
* Default rules ar in the [ defaultRules.js ]
*
* example: rules : {
* field1: {
* number: true,
* required: true
* },
* field2: {
* email: true,
* space: /\b/
* }
* }
* messages : {
* field1: {
* number: 'Please Input A Valid Number !',
* required: 'Please Input Field1 !'
* }
* }
*/
import React from 'react';
import ReactDom from 'react-dom';
import _defaultRules from './defaultRules';
import _defaultMessages from './defaultMessages';
import assign from 'object-assign';
require('./ValidateableForm.css');
let __OriginFromSubmitHandler = function(){};
const _defaultMessage = 'Input is not valid.';
function insertMessageAfterInput (messages){
let inputClassName = this.className.split(/\s+/);
if(inputClassName.indexOf('text-red') === -1){
inputClassName.push('text-red');
}
else {
//Do Noting
}
this.className = inputClassName.join(' ');
if(this.nextSibling && this.nextSibling.className === 'validate-message'){
this.nextSibling.innerText = messages[0];
}
else{
let messageNode = document.createElement('span');
messageNode.innerText = messages[0];
messageNode.className = 'validate-message';
if(this.nextSibling && this.parentNode){
this.parentNode.insertBefore(messageNode, this.nextSibling);
}
else if(this.parentNode) {
this.parentNode.appendChild(messageNode);
}
else {
throw "Don't have a parent Node? Impossible!"
}
}
}
function deleteMessageAfterInput (){
let inputClassName = this.className.split(/\s+/);
while(inputClassName.indexOf('text-red') !== -1){
inputClassName.splice(inputClassName.indexOf('text-red'), 1);
}
this.className = inputClassName.join(' ');
if(this.nextSibling && this.nextSibling.className === 'validate-message'){
this.nextSibling.innerText = '';
}
else {
//Do Nothing
}
}
const VFrom = React.createClass({
getDefaultProps (){
return {
rules: {},
messages: {},
onSubmit(){},
messageClassName: ''
}
},
getInitialState (){
return {
fitRule: true,
messages: []
}
},
findChildInputByName (name){
const _theForm = ReactDom.findDOMNode(this.refs['vForm']);
return _theForm.querySelector('[name=' + name + ']');
},
addChangeValidator (name){
const rules = assign({}, this.props.rules[name]);
return this.validate(rules, this.props.messages[name] || {});
},
validate (rules, messages){
return (event) => {
let value = event.target.value,
testFlag = true,
popMessages = [],
input = event.target;
for(let i in rules){
if(rules.hasOwnProperty(i) && rules[i]){
if(Object.prototype.toString.call(rules[i]) === '[object RegExp]'){
//If the rule itself is a RegExp Object
if(!rules[i].test(value)){
//If you break the rules
testFlag = false;
popMessages.push(messages[i] || _defaultMessage);
}
else {
//Do Nothing
}
}
else if(Object.prototype.toString.call(rules[i]) === '[object Function]'){
//If the rule itself is a Function.
if(!rules[i](value)){
testFlag = false;
popMessages.push(messages[i] || _defaultMessage);
}
else {
//Do Nothing
}
}
else {
if(!_defaultRules[i]){
if(!_defaultRules['_NOT_' + i]){ //没有这条规则
throw 'ERROR: Rule: ' + i + ' is not defined.';
}
else { //If there is a anti-rule of this current rule
if(_defaultRules['_NOT_' + i].test(value)){
testFlag = false;
popMessages.push(messages[i] || _defaultMessages[i]);
}
else {
//Do Nothing
}
}
}
else { //If there is a Default Rule.
if(Object.prototype.toString.call(_defaultRules[i]) === '[object RegExp]'){
if(!_defaultRules[i].test(value)){
testFlag = false;
popMessages.push(messages[i] || _defaultMessages[i]);
}
else {
//Do Nothing
}
}
else if(Object.prototype.toString.call(_defaultRules[i]) === '[object Function]') {
if(!_defaultRules[i](rules[i], value)){
testFlag = false;
popMessages.push(messages[i] || (_defaultMessages[i] + rules[i]));
}
}
}
}
}
}
if(testFlag){
deleteMessageAfterInput.call(input, popMessages);
}
else {
insertMessageAfterInput.call(input, popMessages);
}
return testFlag;
}
},
componentDidMount (){
const rules = this.props.rules;
if(this.refs['vForm']){
const _theForm = ReactDom.findDOMNode(this.refs['vForm']);
_theForm.addEventListener('submit', this.valid);
for(let i in rules){
if(rules.hasOwnProperty(i)){
let input = this.findChildInputByName(i);
if(input){
input.onkeyup = this.addChangeValidator(i);
}
else {
throw 'ERROR: There is no input name as :' + i + ' !'
}
}
}
}
else {
throw 'ERROR: Did not found a Form to validate. Make sure you set the ref of the Form as "vForm".'
}
},
valid (event){
if(this.refs['vForm']){
const rules = this.props.rules;
let testFlag = true;
for(let i in rules){
if(rules.hasOwnProperty(i)){
let input = this.findChildInputByName(i);
if(input){
testFlag = this.validate(this.props.rules[i], this.props.messages[i] || {})({target: input});
}
else {
throw 'ERROR: There is no input name as :' + i + ' !'
}
}
}
if(!testFlag){
event.preventDefault();
event.stopPropagation();
}
else {
this.props.onSubmit(event);
}
}
else {
throw 'ERROR: Did not found a Form to validate. Make sure you set the ref of the Form as "vForm".'
}
},
render (){
return(
<div>
{React.Children.map(this.props.children, (element) => {
return React.cloneElement(element, { ref: element.ref });
})}
</div>
)
}
});
export default VFrom;
module.exports = VFrom;