Skip to content

Commit 2459716

Browse files
jdkahnyouluna
authored andcommitted
fix(Field): getValues return initValue, close #792 (#807)
* fix(Field): getValues return initValue, close #792 - if getValues is called before init, should return initValue - getIn, setIn unit tests
1 parent a815d80 commit 2459716

File tree

7 files changed

+660
-157
lines changed

7 files changed

+660
-157
lines changed

docs/field/demo/topath-defaults.md

-74
This file was deleted.

docs/field/demo/topath.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ import { Input, Button, Field } from '@alifd/next';
2525

2626
class App extends React.Component {
2727
field = new Field(this, {
28-
parseName: true
28+
parseName: true,
29+
values: {
30+
objWithDefaults: {
31+
a: 1,
32+
b: 2
33+
}
34+
}
2935
});
3036

3137
onGetValue() {
@@ -43,7 +49,7 @@ class App extends React.Component {
4349
}
4450

4551
render() {
46-
const { init, reset } = this.field;
52+
const { init, reset, resetToDefault } = this.field;
4753

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

66+
<h3>Object with Defaults</h3>
67+
objWithDefaults.a: <Input {...init('objWithDefaults.a')} /> &nbsp;
68+
objWithDefaults.b: <Input {...init('objWithDefaults.b')} />
69+
<br/><br/>
70+
6071
result:
6172
<pre>{JSON.stringify(this.field.getValues(), null, 2)}</pre>
6273

@@ -65,6 +76,7 @@ class App extends React.Component {
6576
<Button type="primary" onClick={this.onGetValue.bind(this)}>getValues</Button>
6677
<Button onClick={this.onSetValue.bind(this)}>setValues</Button>
6778
<Button onClick={() => reset()}>reset</Button>
79+
<Button onClick={() => resetToDefault()}>resetToDefault</Button>
6880
</div>);
6981
}
7082
}

src/field/index.js

+88-35
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
getParams,
99
setIn,
1010
getIn,
11+
deleteIn,
1112
mapValidateRules,
1213
} from './utils';
1314

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

3437
this.options = Object.assign(
3538
{
@@ -89,6 +92,8 @@ class Field {
8992
getValueFromEvent = null,
9093
autoValidate = true,
9194
} = fieldOption;
95+
const { parseName } = this.options;
96+
9297
const originalProps = Object.assign({}, props, rprops);
9398
const defaultValueName = `default${valueName[0].toUpperCase()}${valueName.slice(
9499
1
@@ -100,11 +105,10 @@ class Field {
100105
defaultValue = initValue;
101106
} else if (originalProps[defaultValueName]) {
102107
defaultValue = originalProps[defaultValueName];
103-
} else if (this.options.parseName) {
104-
defaultValue = getIn(this.initValue, name);
108+
} else if (parseName) {
109+
defaultValue = getIn(this.values, name);
105110
} else {
106-
defaultValue =
107-
(this.initValue && this.initValue[name]) || undefined;
111+
defaultValue = (this.values && this.values[name]) || undefined;
108112
}
109113

110114
Object.assign(field, {
@@ -125,6 +129,11 @@ class Field {
125129
if (!('value' in field)) {
126130
field.value = defaultValue;
127131
}
132+
if (parseName && !getIn(this.values, name)) {
133+
this.values = setIn(this.values, name, field.value);
134+
} else if (!parseName && !this.values[name]) {
135+
this.values[name] = field.value;
136+
}
128137

129138
// Component props
130139
const inputProps = {
@@ -201,6 +210,12 @@ class Field {
201210
? field.getValueFromEvent.apply(this, others)
202211
: getValueFromEvent(e);
203212

213+
if (this.options.parseName) {
214+
this.values = setIn(this.values, name, field.value);
215+
} else {
216+
this.values[name] = field.value;
217+
}
218+
204219
this._resetError(name);
205220

206221
// validate while onChange
@@ -248,14 +263,19 @@ class Field {
248263
const cache = this.fieldsMeta[name];
249264
this._setCache(name, key, cache);
250265
// after destroy, delete data
251-
delete this.fieldsMeta[name];
252266
delete this.instance[name];
267+
this.remove(name);
253268
return;
254269
}
255270

256271
// 2. _saveRef(B, ref) (eg: same name but different compoent may be here)
257272
if (autoUnmount && !this.fieldsMeta[name]) {
258273
this.fieldsMeta[name] = this._getCache(name, key);
274+
this.setValue(
275+
name,
276+
this.fieldsMeta[name] && this.fieldsMeta[name].value,
277+
false
278+
);
259279
}
260280

261281
// only one time here
@@ -312,45 +332,39 @@ class Field {
312332
}
313333

314334
getValue(name) {
315-
const field = this._get(name);
316-
317-
if (field && 'value' in field) {
318-
return field.value;
335+
if (this.options.parseName) {
336+
return getIn(this.values, name);
319337
}
320-
321-
return undefined;
338+
return this.values[name];
322339
}
323340

324341
/**
325342
* 1. get values by names.
326-
* 2. ignore disabled value.
343+
* 2. If no names passed, return shallow copy of `field.values`
327344
* @param {Array} names
328345
*/
329346
getValues(names) {
330-
const fields = names || this.getNames();
331-
let allValues = {};
347+
const allValues = {};
348+
349+
if (names && names.length) {
350+
names.forEach(name => {
351+
allValues[name] = this.getValue(name);
352+
});
353+
} else {
354+
Object.assign(allValues, this.values);
355+
}
332356

333-
fields.forEach(f => {
334-
if (f.disabled) {
335-
return;
336-
}
337-
if (!this.options.parseName) {
338-
allValues[f] = this.getValue(f);
339-
} else {
340-
allValues = setIn(allValues, f, this.getValue(f));
341-
}
342-
});
343357
return allValues;
344358
}
345359

346360
setValue(name, value, reRender = true) {
347361
if (name in this.fieldsMeta) {
348362
this.fieldsMeta[name].value = value;
363+
}
364+
if (this.options.parseName) {
365+
this.values = setIn(this.values, name, value);
349366
} else {
350-
// if not exist, then new one
351-
this.fieldsMeta[name] = {
352-
value,
353-
};
367+
this.values[name] = value;
354368
}
355369
reRender && this._reRender();
356370
}
@@ -361,11 +375,22 @@ class Field {
361375
this.setValue(name, fieldsValue[name], false);
362376
});
363377
} else {
378+
// NOTE: this is a shallow merge
379+
// 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}}}
380+
this.values = Object.assign({}, this.values, fieldsValue);
364381
const fields = this.getNames();
365382
fields.forEach(name => {
366-
const value = getIn(fieldsValue, name);
383+
const value = getIn(this.values, name);
367384
if (value !== undefined) {
368-
this.setValue(name, value, false);
385+
// copy over values that are in this.values
386+
this.fieldsMeta[name].value = value;
387+
} else {
388+
// if no value then copy values from fieldsMeta to keep initialized component data
389+
this.values = setIn(
390+
this.values,
391+
name,
392+
this.fieldsMeta[name].value
393+
);
369394
}
370395
});
371396
}
@@ -586,9 +611,12 @@ class Field {
586611
let changed = false;
587612

588613
const names = ns || Object.keys(this.fieldsMeta);
614+
615+
if (!ns) {
616+
this.values = {};
617+
}
589618
names.forEach(name => {
590619
const field = this._get(name);
591-
this.getValue(name);
592620
if (field) {
593621
changed = true;
594622

@@ -598,6 +626,12 @@ class Field {
598626
delete field.errors;
599627
delete field.rules;
600628
delete field.rulesMap;
629+
630+
if (this.options.parseName) {
631+
this.values = setIn(this.values, name, field.value);
632+
} else {
633+
this.values[name] = field.value;
634+
}
601635
}
602636
});
603637

@@ -641,11 +675,20 @@ class Field {
641675
if (typeof ns === 'string') {
642676
ns = [ns];
643677
}
678+
if (!ns) {
679+
this.values = {};
680+
}
681+
644682
const names = ns || Object.keys(this.fieldsMeta);
645683
names.forEach(name => {
646684
if (name in this.fieldsMeta) {
647685
delete this.fieldsMeta[name];
648686
}
687+
if (this.options.parseName) {
688+
this.values = deleteIn(this.values, name);
689+
} else {
690+
delete this.values[name];
691+
}
649692
});
650693
}
651694

@@ -660,12 +703,14 @@ class Field {
660703
return;
661704
}
662705

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

666710
let list = [];
667711
const names = this.getNames();
668712
names.forEach(n => {
713+
// is name in the target array?
669714
const ret = keyReg.exec(n);
670715
if (ret) {
671716
const index = parseInt(ret[1]);
@@ -684,12 +729,20 @@ class Field {
684729
if (list.length > 0 && list[0].index === startIndex + 1) {
685730
list.forEach(l => {
686731
const n = keyMatch.replace('{index}', l.index - 1);
687-
this.fieldsMeta[n] = this.fieldsMeta[l.name];
732+
const v = this.getValue(l.name);
733+
this.setValue(n, v, false);
688734
});
735+
this.remove(list[list.length - 1].name);
689736

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

692-
this._reRender();
741+
if (parent) {
742+
// if parseName=true then parent is an Array object but does not know an element was removed
743+
// this manually decrements the array length
744+
parent.length--;
745+
}
693746
}
694747
}
695748

0 commit comments

Comments
 (0)