Skip to content

Commit 73664c8

Browse files
author
Vlad Balin
committed
Added error messages from validator functions
1 parent 9e944d1 commit 73664c8

File tree

6 files changed

+44
-24
lines changed

6 files changed

+44
-24
lines changed

example/userslist.jsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import React, {PropTypes} from 'react'
55

66
import Link from 'valuelink'
77
import Modal from 'react-modal'
8-
import {Input} from 'tags.jsx'
8+
import {Input, isRequired, isEmail } from 'tags.jsx'
99

1010
export const UsersList = React.createClass( {
1111
getInitialState(){
@@ -84,9 +84,6 @@ const UserRow = ( { userLink, onEdit } ) =>{
8484
)
8585
};
8686

87-
88-
const emailPattern = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i;
89-
9087
const EditUser = React.createClass( {
9188
propTypes : {
9289
userLink : PropTypes.instanceOf( Link ).isRequired,
@@ -122,12 +119,12 @@ const EditUser = React.createClass( {
122119
const linked = Link.all( this, 'name', 'email', 'isActive' );
123120

124121
linked.name
125-
.check( x => x, 'Name is required' )
122+
.check( isRequired )
126123
.check( x => x.indexOf( ' ' ) < 0, 'Spaces are not allowed' );
127124

128125
linked.email
129-
.check( x => x, 'Email is required' )
130-
.check( x => x.match( emailPattern ), 'Email is invalid' );
126+
.check( isRequired )
127+
.check( isEmail );
131128

132129
return (
133130
<form onSubmit={ this.onSubmit }>

tags.jsx

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* WTFPL License, (c) 2016 Vlad Balin, Volicon.
55
*/
66

7+
78
import React, { PropTypes } from 'react'
89

910
const setValue = ( x, e ) => e.target.value;
@@ -18,35 +19,51 @@ const setBoolValue = ( x, e ) => Boolean( e.target.checked );
1819
* <input type="text" valueLink={ linkToString } />
1920
*/
2021

21-
export const Input = ( { invalid = 'invalid', className = '', valueLink, checkedLink, ...props } ) =>{
22-
const type = props.type,
22+
23+
function validationClasses( props, value, error ){
24+
let classNames = props.className ? [ props.className ] : [];
25+
26+
if( error ){
27+
classNames.push( props.invalidClass || 'invalid' );
28+
29+
if( value === '' ){
30+
classNames.push( props.requiredClass || 'required' );
31+
}
32+
}
33+
34+
return classNames.join( ' ' );
35+
}
36+
37+
export const Input = ( props ) =>{
38+
const { valueLink, checkedLink, ...rest } = props,
39+
type = props.type,
2340
link = valueLink || checkedLink;
2441

2542
switch( type ){
2643
case 'checkbox':
2744
return <input {...props}
28-
className={ className }
2945
checked={ link.value }
3046
onChange={ link.action( setBoolValue ) }/>;
3147

3248
case 'radio' :
3349
return <input {...props}
34-
className={ className }
3550
checked={ link.value === props.value }
3651
onChange={ e => { e.target.checked && link.set( props.value ) } }/>;
3752

3853
default:
3954
return <input {...props}
40-
className={ valueLink.error ? invalid + ' ' + className : className }
55+
className={ validationClasses( rest, valueLink.value, valueLink.error ) }
4156
value={ valueLink.value }
4257
onChange={ valueLink.action( setValue ) }/>;
4358
}
4459
};
4560

4661
export const isRequired = x => x != null && x !== '';
62+
isRequired.error = 'Required';
4763

4864
const emailPattern = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i;
4965
export const isEmail = x => x.match( emailPattern );
66+
isEmail.error = 'Should be valid email';
5067

5168
// This number component rejects invalid input and modify link only with valid number values.
5269
// Implementing numeric input rejection might be tricky.
@@ -65,7 +82,7 @@ export const NumberInput = React.createClass( {
6582
setValue( x ){
6683
// We're not using native state in order to avoid race condition.
6784
this.value = String( x );
68-
this.error = isNaN( Number( x ) );
85+
this.error = this.value === '' || isNaN( Number( x ) );
6986
this.forceUpdate();
7087
},
7188

@@ -92,15 +109,15 @@ export const NumberInput = React.createClass( {
92109
},
93110

94111
render(){
95-
const { type, invalid = 'invalid', className = '', valueLink, ...props } = this.props,
112+
const { valueLink, ...props } = this.props,
96113
error = valueLink.error || this.error;
97114

98-
return <input type="text"
99-
className={ error ? className + ' ' + invalid : className }
115+
return <input { ...props }
116+
type="text"
117+
className={ validationClasses( props, this.value, error ) }
100118
value={ this.value }
101119
onKeyPress={ this.onKeyPress }
102120
onChange={ this.onChange }
103-
{ ...props }
104121
/>;
105122
},
106123

@@ -142,9 +159,9 @@ export const NumberInput = React.createClass( {
142159
*
143160
* <TextArea valueLink={ linkToText } />
144161
*/
145-
export const TextArea = ( { invalid = 'invalid', className = '', valueLink, ...props } ) => (
162+
export const TextArea = ( { valueLink, ...props } ) => (
146163
<textarea {...props}
147-
className={ valueLink.error ? invalid + ' ' + className : className }
164+
className={ validationClasses( props, valueLink.value , valueLink.error ) }
148165
value={ valueLink.value }
149166
onChange={ valueLink.action( setValue ) }/>
150167
);

valuelink.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
*/
66
export declare type Transform<T> = (value: T, event?: {}) => T;
77
export declare type EventHandler = (event: {}) => void;
8-
export declare type Validator<T> = (value: T) => boolean;
8+
export interface Validator<T> {
9+
(value: T): boolean;
10+
error?: any;
11+
}
912
export declare type Iterator = (link: ChainedLink, key: string | number) => any;
1013
export declare type StateLinks = {
1114
[attrName: string]: StateLink<any>;

valuelink.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)