Skip to content

Commit

Permalink
fix(Field): getValues return initValue, close #792 (#807)
Browse files Browse the repository at this point in the history
* fix(Field): getValues return initValue, close #792 
- if getValues is called before init, should return initValue
- getIn, setIn unit tests
  • Loading branch information
jdkahn authored and youluna committed Jul 3, 2019
1 parent a815d80 commit 2459716
Show file tree
Hide file tree
Showing 7 changed files with 660 additions and 157 deletions.
74 changes: 0 additions & 74 deletions docs/field/demo/topath-defaults.md

This file was deleted.

16 changes: 14 additions & 2 deletions docs/field/demo/topath.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ import { Input, Button, Field } from '@alifd/next';

class App extends React.Component {
field = new Field(this, {
parseName: true
parseName: true,
values: {
objWithDefaults: {
a: 1,
b: 2
}
}
});

onGetValue() {
Expand All @@ -43,7 +49,7 @@ class App extends React.Component {
}

render() {
const { init, reset } = this.field;
const { init, reset, resetToDefault } = this.field;

return (<div className="demo">
<h3>Object transfer</h3>
Expand All @@ -57,6 +63,11 @@ class App extends React.Component {
arr.1: <Input {...init('arr.1', {initValue: '1'})} />
<br/><br/>

<h3>Object with Defaults</h3>
objWithDefaults.a: <Input {...init('objWithDefaults.a')} /> &nbsp;
objWithDefaults.b: <Input {...init('objWithDefaults.b')} />
<br/><br/>

result:
<pre>{JSON.stringify(this.field.getValues(), null, 2)}</pre>

Expand All @@ -65,6 +76,7 @@ class App extends React.Component {
<Button type="primary" onClick={this.onGetValue.bind(this)}>getValues</Button>
<Button onClick={this.onSetValue.bind(this)}>setValues</Button>
<Button onClick={() => reset()}>reset</Button>
<Button onClick={() => resetToDefault()}>resetToDefault</Button>
</div>);
}
}
Expand Down
123 changes: 88 additions & 35 deletions src/field/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
getParams,
setIn,
getIn,
deleteIn,
mapValidateRules,
} from './utils';

Expand All @@ -29,7 +30,9 @@ class Field {
this.fieldsMeta = {};
this.cachedBind = {};
this.instance = {};
this.initValue = options.values || {};
// holds constructor values. Used for setting field defaults on init if no other value or initValue is passed.
// Also used caching values when using `parseName: true` before a field is initialized
this.values = options.values || {};

this.options = Object.assign(
{
Expand Down Expand Up @@ -89,6 +92,8 @@ class Field {
getValueFromEvent = null,
autoValidate = true,
} = fieldOption;
const { parseName } = this.options;

const originalProps = Object.assign({}, props, rprops);
const defaultValueName = `default${valueName[0].toUpperCase()}${valueName.slice(
1
Expand All @@ -100,11 +105,10 @@ class Field {
defaultValue = initValue;
} else if (originalProps[defaultValueName]) {
defaultValue = originalProps[defaultValueName];
} else if (this.options.parseName) {
defaultValue = getIn(this.initValue, name);
} else if (parseName) {
defaultValue = getIn(this.values, name);
} else {
defaultValue =
(this.initValue && this.initValue[name]) || undefined;
defaultValue = (this.values && this.values[name]) || undefined;
}

Object.assign(field, {
Expand All @@ -125,6 +129,11 @@ class Field {
if (!('value' in field)) {
field.value = defaultValue;
}
if (parseName && !getIn(this.values, name)) {
this.values = setIn(this.values, name, field.value);
} else if (!parseName && !this.values[name]) {
this.values[name] = field.value;
}

// Component props
const inputProps = {
Expand Down Expand Up @@ -201,6 +210,12 @@ class Field {
? field.getValueFromEvent.apply(this, others)
: getValueFromEvent(e);

if (this.options.parseName) {
this.values = setIn(this.values, name, field.value);
} else {
this.values[name] = field.value;
}

this._resetError(name);

// validate while onChange
Expand Down Expand Up @@ -248,14 +263,19 @@ class Field {
const cache = this.fieldsMeta[name];
this._setCache(name, key, cache);
// after destroy, delete data
delete this.fieldsMeta[name];
delete this.instance[name];
this.remove(name);
return;
}

// 2. _saveRef(B, ref) (eg: same name but different compoent may be here)
if (autoUnmount && !this.fieldsMeta[name]) {
this.fieldsMeta[name] = this._getCache(name, key);
this.setValue(
name,
this.fieldsMeta[name] && this.fieldsMeta[name].value,
false
);
}

// only one time here
Expand Down Expand Up @@ -312,45 +332,39 @@ class Field {
}

getValue(name) {
const field = this._get(name);

if (field && 'value' in field) {
return field.value;
if (this.options.parseName) {
return getIn(this.values, name);
}

return undefined;
return this.values[name];
}

/**
* 1. get values by names.
* 2. ignore disabled value.
* 2. If no names passed, return shallow copy of `field.values`
* @param {Array} names
*/
getValues(names) {
const fields = names || this.getNames();
let allValues = {};
const allValues = {};

if (names && names.length) {
names.forEach(name => {
allValues[name] = this.getValue(name);
});
} else {
Object.assign(allValues, this.values);
}

fields.forEach(f => {
if (f.disabled) {
return;
}
if (!this.options.parseName) {
allValues[f] = this.getValue(f);
} else {
allValues = setIn(allValues, f, this.getValue(f));
}
});
return allValues;
}

setValue(name, value, reRender = true) {
if (name in this.fieldsMeta) {
this.fieldsMeta[name].value = value;
}
if (this.options.parseName) {
this.values = setIn(this.values, name, value);
} else {
// if not exist, then new one
this.fieldsMeta[name] = {
value,
};
this.values[name] = value;
}
reRender && this._reRender();
}
Expand All @@ -361,11 +375,22 @@ class Field {
this.setValue(name, fieldsValue[name], false);
});
} else {
// NOTE: this is a shallow merge
// Ex. we have two values a.b.c=1 ; a.b.d=2, and use setValues({a:{b:{c:3}}}) , then because of shallow merge a.b.d will be lost, we will get only {a:{b:{c:3}}}
this.values = Object.assign({}, this.values, fieldsValue);
const fields = this.getNames();
fields.forEach(name => {
const value = getIn(fieldsValue, name);
const value = getIn(this.values, name);
if (value !== undefined) {
this.setValue(name, value, false);
// copy over values that are in this.values
this.fieldsMeta[name].value = value;
} else {
// if no value then copy values from fieldsMeta to keep initialized component data
this.values = setIn(
this.values,
name,
this.fieldsMeta[name].value
);
}
});
}
Expand Down Expand Up @@ -586,9 +611,12 @@ class Field {
let changed = false;

const names = ns || Object.keys(this.fieldsMeta);

if (!ns) {
this.values = {};
}
names.forEach(name => {
const field = this._get(name);
this.getValue(name);
if (field) {
changed = true;

Expand All @@ -598,6 +626,12 @@ class Field {
delete field.errors;
delete field.rules;
delete field.rulesMap;

if (this.options.parseName) {
this.values = setIn(this.values, name, field.value);
} else {
this.values[name] = field.value;
}
}
});

Expand Down Expand Up @@ -641,11 +675,20 @@ class Field {
if (typeof ns === 'string') {
ns = [ns];
}
if (!ns) {
this.values = {};
}

const names = ns || Object.keys(this.fieldsMeta);
names.forEach(name => {
if (name in this.fieldsMeta) {
delete this.fieldsMeta[name];
}
if (this.options.parseName) {
this.values = deleteIn(this.values, name);
} else {
delete this.values[name];
}
});
}

Expand All @@ -660,12 +703,14 @@ class Field {
return;
}

// regex to match field names in the same target array
const reg = keyMatch.replace('{index}', '(\\d+)');
const keyReg = new RegExp(`^${reg}$`);

let list = [];
const names = this.getNames();
names.forEach(n => {
// is name in the target array?
const ret = keyReg.exec(n);
if (ret) {
const index = parseInt(ret[1]);
Expand All @@ -684,12 +729,20 @@ class Field {
if (list.length > 0 && list[0].index === startIndex + 1) {
list.forEach(l => {
const n = keyMatch.replace('{index}', l.index - 1);
this.fieldsMeta[n] = this.fieldsMeta[l.name];
const v = this.getValue(l.name);
this.setValue(n, v, false);
});
this.remove(list[list.length - 1].name);

delete this.fieldsMeta[list[list.length - 1].name];
let parentName = keyMatch.replace('.{index}', '');
parentName = parentName.replace('[{index}]', '');
const parent = this.getValue(parentName);

this._reRender();
if (parent) {
// if parseName=true then parent is an Array object but does not know an element was removed
// this manually decrements the array length
parent.length--;
}
}
}

Expand Down
Loading

0 comments on commit 2459716

Please sign in to comment.