1
1
import React , { Component , Children , isValidElement , cloneElement } from 'react' ;
2
2
import { polyfill } from 'react-lifecycles-compat' ;
3
3
import PropTypes from 'prop-types' ;
4
- import cloneDeep from 'lodash.clonedeep' ;
5
4
import classNames from 'classnames' ;
6
5
import Select from '../select' ;
7
6
import Tree from '../tree' ;
@@ -13,6 +12,7 @@ import {
13
12
isDescendantOrSelf ,
14
13
} from '../tree/view/util' ;
15
14
import { func , obj , KEYCODE } from '../util' ;
15
+ import { getValueDataSource , valueToSelectKey } from '../select/util' ;
16
16
17
17
const noop = ( ) => { } ;
18
18
const { Node : TreeNode } = Tree ;
@@ -165,14 +165,19 @@ class TreeSelect extends Component {
165
165
* 数据源,该属性优先级高于 children
166
166
*/
167
167
dataSource : PropTypes . arrayOf ( PropTypes . object ) ,
168
+ /**
169
+ * value/defaultValue 在 dataSource 中不存在时,是否展示
170
+ * @version 1.25
171
+ */
172
+ preserveNonExistentValue : PropTypes . bool ,
168
173
/**
169
174
* (受控)当前值
170
175
*/
171
- value : PropTypes . oneOfType ( [ PropTypes . string , PropTypes . arrayOf ( PropTypes . string ) ] ) ,
176
+ value : PropTypes . oneOfType ( [ PropTypes . string , PropTypes . object , PropTypes . arrayOf ( PropTypes . any ) ] ) ,
172
177
/**
173
178
* (非受控)默认值
174
179
*/
175
- defaultValue : PropTypes . oneOfType ( [ PropTypes . string , PropTypes . arrayOf ( PropTypes . string ) ] ) ,
180
+ defaultValue : PropTypes . oneOfType ( [ PropTypes . string , PropTypes . object , PropTypes . arrayOf ( PropTypes . any ) ] ) ,
176
181
/**
177
182
* 选中值改变时触发的回调函数
178
183
* @param {String|Array } value 选中的值,单选时返回单个值,多选时返回数组
@@ -306,12 +311,18 @@ class TreeSelect extends Component {
306
311
defaultVisible : false ,
307
312
onVisibleChange : noop ,
308
313
useVirtual : false ,
314
+ /**
315
+ * TODO
316
+ * 目前 select/cascade select 是默认支持的,在 2.x 版本中 tree-select 也将默认支持
317
+ */
318
+ preserveNonExistentValue : false ,
309
319
} ;
310
320
311
321
constructor ( props , context ) {
312
322
super ( props , context ) ;
313
323
314
324
const { defaultVisible, visible, defaultValue, value } = props ;
325
+
315
326
this . state = {
316
327
visible : typeof visible === 'undefined' ? defaultVisible : visible ,
317
328
value : normalizeToArray ( typeof value === 'undefined' ? defaultValue : value ) ,
@@ -320,9 +331,19 @@ class TreeSelect extends Component {
320
331
searchedKeys : [ ] ,
321
332
retainedKeys : [ ] ,
322
333
autoExpandParent : false ,
334
+ // map of value => item, includes value not exist in dataSource
335
+ mapValueDS : { } ,
323
336
...flatDataSource ( props ) ,
324
337
} ;
325
338
339
+ // init value/mapValueDS when defaultValue is not undefined
340
+ if ( this . state . value !== undefined ) {
341
+ this . state . mapValueDS = getValueDataSource ( this . state . value , this . state . mapValueDS ) . mapValueDS ;
342
+ this . state . value = this . state . value . map ( v => {
343
+ return valueToSelectKey ( v ) ;
344
+ } ) ;
345
+ }
346
+
326
347
bindCtx ( this , [
327
348
'handleSelect' ,
328
349
'handleCheck' ,
@@ -342,7 +363,13 @@ class TreeSelect extends Component {
342
363
const st = { } ;
343
364
344
365
if ( 'value' in props ) {
345
- st . value = normalizeToArray ( props . value ) ;
366
+ const valueArray = normalizeToArray ( props . value ) ;
367
+ // convert value to string[]
368
+ st . value = valueArray . map ( v => {
369
+ return valueToSelectKey ( v ) ;
370
+ } ) ;
371
+ // re-calculate map
372
+ st . mapValueDS = getValueDataSource ( props . value , state . mapValueDS ) . mapValueDS ;
346
373
}
347
374
if ( 'visible' in props ) {
348
375
st . visible = props . visible ;
@@ -370,7 +397,6 @@ class TreeSelect extends Component {
370
397
if ( k ) {
371
398
ret . push ( k ) ;
372
399
}
373
-
374
400
return ret ;
375
401
} , [ ] ) ;
376
402
}
@@ -381,6 +407,7 @@ class TreeSelect extends Component {
381
407
382
408
getValueForSelect ( value ) {
383
409
const { treeCheckedStrategy } = this . props ;
410
+ const nonExistentValueKeys = this . getNonExistentValueKeys ( ) ;
384
411
385
412
let keys = this . getKeysByValue ( value ) ;
386
413
keys = getAllCheckedKeys ( keys , this . state . _k2n , this . state . _p2n ) ;
@@ -396,11 +423,16 @@ class TreeSelect extends Component {
396
423
break ;
397
424
}
398
425
399
- return this . getValueByKeys ( keys ) ;
426
+ const values = this . getValueByKeys ( keys ) ;
427
+
428
+ return [ ...values , ...nonExistentValueKeys ] ;
400
429
}
401
430
402
431
getData ( value , forSelect ) {
403
- return value . reduce ( ( ret , v ) => {
432
+ const { preserveNonExistentValue } = this . props ;
433
+ const { mapValueDS } = this . state ;
434
+
435
+ const ret = value . reduce ( ( ret , v ) => {
404
436
const k = this . state . _v2n [ v ] && this . state . _v2n [ v ] . key ;
405
437
if ( k ) {
406
438
const { label, pos, disabled, checkboxDisabled } = this . state . _k2n [ k ] ;
@@ -415,10 +447,38 @@ class TreeSelect extends Component {
415
447
d . key = k ;
416
448
}
417
449
ret . push ( d ) ;
450
+ } else if ( preserveNonExistentValue ) {
451
+ // 需要保留 dataSource 中不存在的 value
452
+ const item = mapValueDS [ v ] ;
453
+ if ( item ) {
454
+ ret . push ( item ) ;
455
+ }
418
456
}
419
-
420
457
return ret ;
421
458
} , [ ] ) ;
459
+
460
+ return ret ;
461
+ }
462
+
463
+ getNonExistentValues ( ) {
464
+ const { preserveNonExistentValue } = this . props ;
465
+ const { value } = this . state ;
466
+
467
+ if ( ! preserveNonExistentValue ) {
468
+ return [ ] ;
469
+ }
470
+ const nonExistentValues = value . filter ( v => ! this . state . _v2n [ v ] ) ;
471
+ return nonExistentValues ;
472
+ }
473
+
474
+ getNonExistentValueKeys ( ) {
475
+ const nonExistentValues = this . getNonExistentValues ( ) ;
476
+ return nonExistentValues . map ( v => {
477
+ if ( typeof v === 'object' && v . hasOwnProperty ( 'value' ) ) {
478
+ return v . value ;
479
+ }
480
+ return v ;
481
+ } ) ;
422
482
}
423
483
424
484
saveTreeRef ( ref ) {
@@ -448,7 +508,10 @@ class TreeSelect extends Component {
448
508
const { selected } = extra ;
449
509
450
510
if ( multiple || selected ) {
451
- const value = this . getValueByKeys ( selectedKeys ) ;
511
+ let value = this . getValueByKeys ( selectedKeys ) ;
512
+ const nonExistentValues = this . getNonExistentValues ( ) ;
513
+ value = [ ...nonExistentValues , ...value ] ;
514
+
452
515
if ( ! ( 'value' in this . props ) ) {
453
516
this . setState ( {
454
517
value,
@@ -468,7 +531,10 @@ class TreeSelect extends Component {
468
531
handleCheck ( checkedKeys ) {
469
532
const { onChange } = this . props ;
470
533
471
- const value = this . getValueByKeys ( checkedKeys ) ;
534
+ let value = this . getValueByKeys ( checkedKeys ) ;
535
+ const nonExistentValues = this . getNonExistentValues ( ) ;
536
+ value = [ ...nonExistentValues , ...value ] ;
537
+
472
538
if ( ! ( 'value' in this . props ) ) {
473
539
this . setState ( {
474
540
value,
@@ -483,7 +549,14 @@ class TreeSelect extends Component {
483
549
const { treeCheckable, treeCheckStrictly, treeCheckedStrategy, onChange } = this . props ;
484
550
485
551
let value ;
486
- if ( treeCheckable && ! treeCheckStrictly && [ 'parent' , 'all' ] . indexOf ( treeCheckedStrategy ) !== - 1 ) {
552
+ if (
553
+ // there's linkage relationship among nodes
554
+ treeCheckable &&
555
+ ! treeCheckStrictly &&
556
+ [ 'parent' , 'all' ] . indexOf ( treeCheckedStrategy ) !== - 1 &&
557
+ // value exits in datasource
558
+ this . state . _v2n [ removedValue ]
559
+ ) {
487
560
const removedPos = this . state . _v2n [ removedValue ] . pos ;
488
561
value = this . state . value . filter ( v => {
489
562
const p = this . state . _v2n [ v ] . pos ;
@@ -804,9 +877,11 @@ class TreeSelect extends Component {
804
877
isPreview,
805
878
} = this . props ;
806
879
const others = pickOthers ( Object . keys ( TreeSelect . propTypes ) , this . props ) ;
807
- const { value , visible } = this . state ;
880
+ const { visible , value } = this . state ;
808
881
882
+ // if (non-leaf 节点可选 & 父子节点选中状态需要联动),需要额外计算父子节点间的联动关系
809
883
const valueForSelect = treeCheckable && ! treeCheckStrictly ? this . getValueForSelect ( value ) : value ;
884
+
810
885
let data = this . getData ( valueForSelect , true ) ;
811
886
if ( ! multiple && ! treeCheckable ) {
812
887
data = data [ 0 ] ;
0 commit comments