Skip to content

Commit

Permalink
feat(Field): add api autoValidate=false to close onChange validate
Browse files Browse the repository at this point in the history
  • Loading branch information
bindoon committed Feb 2, 2019
1 parent 484841b commit b9b0129
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 32 deletions.
6 changes: 3 additions & 3 deletions docs/field/demo/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ class App extends React.Component {
<br/>
<br/>

<Input multiple maxLength={10} defaultValue=">3 and <10" {...init('textarea', {
<Input.TextArea placeholder=">3 and <10" {...init('textarea', {
rules: [{
required: true,
min: 3,
max: 10
minLength: 3,
maxLength: 10
}]
})} />
{this.field.getError('textarea') ?
Expand Down
2 changes: 2 additions & 0 deletions docs/field/index.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ Let myfield = new Field(this [,options]);
|forceUpdate | Only the components of PureComponent are recommended to open this forced refresh function, which will cause performance problems (500 components as an example: the render will cost 700ms when it is turned on, and 400ms if it is turned off) | Boolean |false|
| scrollToFirstError | scrolling field.validate scrolls to the first errored component, offsets if it is an integer | Boolean/Number |true|
| autoUnmount | Automatically delete the Unmout element, if you want to keep the data can be set to false | Boolean |true|
| autoValidate | Automatically validate while value changed | Boolean |true|
| values | initial value| Object ||

#### API Interface
Expand Down Expand Up @@ -225,6 +226,7 @@ init(name, options, props)
| options.rules | Checksum Rules | Array/Object | | | |
| options.getValueFromEvent | custom way to get value from `onChange` event, generally do not need to set. Detailed usage see demo `custom data get` | Function(value, ...args) parameter order and components are exactly the same The | | | |
|props | Component-defined events can be written here | Object | | | |
| autoValidate | Automatically validate while value changed | Boolean |true|

return

Expand Down
2 changes: 2 additions & 0 deletions docs/field/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ let myfield = new Field(this [,options]);
| forceUpdate | 仅建议PureComponent的组件打开此强制刷新功能,会带来性能问题(500个组件为例:打开的时候render花费700ms, 关闭时候render花费400ms) | Boolean |false|
| scrollToFirstError | field.validate的时候滚动到第一个出错的组件, 如果是整数会进行偏移 | Boolean/Number |true|
| autoUnmount | 自动删除Unmout元素,如果想保留数据可以设置为false | Boolean |true|
| autoValidate | 是否修改数据的时候就自动触发校验 | Boolean |true|
| values | 初始化数据 | Object ||

#### API接口
Expand Down Expand Up @@ -229,6 +230,7 @@ init(name, options, props)
| options.rules | 校验规则 | Array/Object | | | |
| options.getValueFromEvent | 自定义从`onChange`事件中获取value的方式,一般不需要设置. 详细用法查看demo `自定义数据获取` | Function(value,...args) 参数顺序和组件是完全一致的 | | | |
| props | 组件自定义的事件可以写在这里 | Object | | | |
| autoValidate | 是否修改数据的时候自动触发校验单个组件的校验 | Boolean |true|

返回值
```
Expand Down
43 changes: 27 additions & 16 deletions src/field/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Field {
first: false,
onChange: func.noop,
autoUnmount: true,
autoValidate: true,
}, options);

['init', 'getValue', 'getValues', 'setValue', 'setValues', 'getError', 'setError', 'setErrors', 'validate', 'getState', 'reset', 'resetToDefault', 'remove', 'spliceArray'].forEach((m) => {
Expand All @@ -51,7 +52,7 @@ class Field {
}

/**
* Control Component
* Controlled Component
* @param {String} name
* @param {Object} fieldOption
* @returns {Object} {value, onChange}
Expand All @@ -63,7 +64,8 @@ class Field {
trigger = 'onChange',
rules = [],
props = {},
getValueFromEvent = null
getValueFromEvent = null,
autoValidate = true,
} = fieldOption;
const originalProps = Object.assign({}, props, rprops);
const defaultValueName = `default${valueName[0].toUpperCase()}${valueName.slice(1)}`;
Expand All @@ -80,7 +82,7 @@ class Field {
ref: originalProps.ref
});

// Control Component
// Controlled Component
if (valueName in originalProps) {
field.value = originalProps[valueName];
}
Expand All @@ -97,21 +99,25 @@ class Field {
[valueName]: field.value
};

// trigger map
const rulesMap = mapValidateRules(field.rules, trigger);
let rulesMap = {};

// validate hook
for (const action in rulesMap) {
if (action === trigger) {
continue;
}
if (this.options.autoValidate && autoValidate !== false) {
// trigger map
rulesMap = mapValidateRules(field.rules, trigger);

const actionRule = rulesMap[action];
inputProps[action] = (...args) => {
this._validate(name, actionRule, action);
this._callPropsEvent(action, originalProps, ...args);
this._reRender();
};
// validate hook
for (const action in rulesMap) {
if (action === trigger) {
continue;
}

const actionRule = rulesMap[action];
inputProps[action] = (...args) => {
this._validate(name, actionRule, action);
this._callPropsEvent(action, originalProps, ...args);
this._reRender();
};
}
}

// onChange hack
Expand Down Expand Up @@ -143,6 +149,9 @@ class Field {
return this.fieldsMeta[name];
}

/**
* update field.value and validate
*/
_callOnChange(name, rule, trigger, ...others) {
const e = others[0];
const field = this._get(name);
Expand All @@ -154,6 +163,8 @@ class Field {
field.value = field.getValueFromEvent ? field.getValueFromEvent.apply(this, others) : getValueFromEvent(e);

this._resetError(name);

// validate while onChange
rule && this._validate(name, rule, trigger);
}

Expand Down
81 changes: 68 additions & 13 deletions test/field/options-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ describe('options', () => {
const init = this.field.init;
return (
<div>
<Input {...init('input')}/> {this.state.show
? < Input { ...init('input2')
} /> : null}
<Input {...init('input')}/> {this.state.show ?
< Input {...init('input2')
} /> : null}
<button onClick={() => {
assert('input2' in this.field.getValues() === false);
done();
Expand Down Expand Up @@ -50,8 +50,8 @@ describe('options', () => {
const init = this.field.init;
return (
<div>
{this.state.show
? < Input { ...init('input') } key="1"/> : <Input {...init('input')} key="2"/>}
{this.state.show ?
< Input {...init('input')} key="1"/> : <Input {...init('input')} key="2"/>}
<button onClick={() => {
assert('input' in this.field.getValues() === true);
}}>click
Expand All @@ -66,14 +66,14 @@ describe('options', () => {

done();
});

it('should support autoUnmount=false', (done) => {

class Demo extends React.Component {
state = {
show: true
}
field = new Field(this, {autoUnmount:false});
field = new Field(this, {autoUnmount: false});

render() {
const init = this.field.init;
Expand All @@ -82,7 +82,7 @@ describe('options', () => {
<Input {...init('input')}/>
{this.state.show ? < Input {...init('input2', {initValue: 'test2'})} /> : null}
<button onClick={() => {
console.log(this.field)
console.log(this.field);
assert(this.field.getValue('input2') === 'test2');
}}>click
</button>
Expand Down Expand Up @@ -111,7 +111,7 @@ describe('options', () => {
<Input {...init('input', {rules: [{required: true, message: 'cant be null'}]})}/>
<button onClick={() => {
this.field.validate((error, value, cb) => {
assert(error['input']['errors'][0] === 'cant be null');
assert(error.input.errors[0] === 'cant be null');
});
}}>click
</button>
Expand Down Expand Up @@ -157,13 +157,13 @@ describe('options', () => {

describe('should support parseName', () => {
it('getValues', (done) => {
let field = new Field(null, {parseName: true});
const field = new Field(null, {parseName: true});
field.init('user.name', {initValue: 'frankqian'});
field.init('user.pwd', {initValue: 12345});
field.init('option[0]', {initValue: 'option1'});
field.init('option[1]', {initValue: 'option2'});

let values = field.getValues();
const values = field.getValues();

assert(Object.keys(values).length === 2);
assert(values.user.name === 'frankqian');
Expand All @@ -175,7 +175,7 @@ describe('options', () => {
done();
});
it('setValues', (done) => {
let field = new Field(null, {parseName: true});
const field = new Field(null, {parseName: true});
field.init('user.name', {initValue: 'frankqian'});
field.init('user.pwd', {initValue: 12345});
field.init('option[0]', {initValue: 'option1'});
Expand All @@ -188,7 +188,7 @@ describe('options', () => {
option: ['test1', 'test2']
});

let values = field.getValues();
const values = field.getValues();

assert(Object.keys(values).length === 2);

Expand All @@ -199,4 +199,59 @@ describe('options', () => {
done();
});
});

describe('should support autoValidate=false', () => {
it('options.autoValidate=true', (done) => {
const field = new Field(null, {autoValidate: true});
const inited = field.init('input', {rules: [{ minLength: 10 }]});

const wrapper = mount(<Input {...inited}/>);
wrapper.find('input').simulate('change', {
target: {
value: 'test'
}
});

assert(field.getError('input') !== null);

done();
});
it('options.autoValidate=false', (done) => {
const field = new Field(null, {autoValidate: false});
const inited = field.init('input', {rules: [{ minLength: 10 }]});

const wrapper = mount(<Input {...inited}/>);
wrapper.find('input').simulate('change', {
target: {
value: 'test'
}
});

assert(field.getError('input') === null);

field.validate('input');
assert(field.getError('input') !== null);

done();
});
it('props.autoValidate=false', (done) => {
const field = new Field(null);
const inited = field.init('input', {autoValidate: false, rules: [{ minLength: 10 }]});

const wrapper = mount(<Input {...inited}/>);
wrapper.find('input').simulate('change', {
target: {
value: 'test'
}
});

assert(field.getError('input') === null);

field.validate('input');
assert(field.getError('input') !== null);

done();
});
});

});

0 comments on commit b9b0129

Please sign in to comment.