fix: fix display association fields with subform (#3036)
* fix: fix display association fields with subform * fix: transformVariableValue * fix: should also to request data when value is null * fix: better way to fix
This commit is contained in:
		
							parent
							
								
									887ddf0ed1
								
							
						
					
					
						commit
						c25f51d99b
					
				| @ -7,6 +7,7 @@ import { useCollection, useCollectionManager } from '../../../../collection-mana | |||||||
| import { useFlag } from '../../../../flag-provider'; | import { useFlag } from '../../../../flag-provider'; | ||||||
| import { useVariables } from '../../../../variables'; | import { useVariables } from '../../../../variables'; | ||||||
| import { transformVariableValue } from '../../../../variables/utils/transformVariableValue'; | import { transformVariableValue } from '../../../../variables/utils/transformVariableValue'; | ||||||
|  | import { isDisplayField, isFieldValueEmpty } from '../utils'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * 用于懒加载 Form 区块中正常的关系字段 |  * 用于懒加载 Form 区块中正常的关系字段 | ||||||
| @ -34,7 +35,8 @@ const useLazyLoadAssociationFieldOfForm = () => { | |||||||
|     if ( |     if ( | ||||||
|       isInAssignFieldValues || |       isInAssignFieldValues || | ||||||
|       _.isEmpty(cloneRecord) || |       _.isEmpty(cloneRecord) || | ||||||
|       (formBlockType === 'create' && !isInSubForm && !isInSubTable) |       (formBlockType === 'create' && !isInSubForm && !isInSubTable) || | ||||||
|  |       isDisplayField(schemaName) | ||||||
|     ) { |     ) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| @ -45,7 +47,7 @@ const useLazyLoadAssociationFieldOfForm = () => { | |||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!variables || record[schemaName] != null) { |     if (!variables || !isFieldValueEmpty(_.get(record, schemaName))) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -67,7 +69,9 @@ const useLazyLoadAssociationFieldOfForm = () => { | |||||||
|         // 3. 所以,当 `变量预加载` 的请求晚于编辑表单的请求时,就会造成这个问题;
 |         // 3. 所以,当 `变量预加载` 的请求晚于编辑表单的请求时,就会造成这个问题;
 | ||||||
|         // 更优的解决方案是:在 `变量预加载` 中也加上子表单中的关系字段路径,并删除编辑表单请求数据的逻辑(因为没必要了)。
 |         // 更优的解决方案是:在 `变量预加载` 中也加上子表单中的关系字段路径,并删除编辑表单请求数据的逻辑(因为没必要了)。
 | ||||||
|         // 但是这样改动较大,可以等之后 e2e 测试较完备后再处理。
 |         // 但是这样改动较大,可以等之后 e2e 测试较完备后再处理。
 | ||||||
|         if (field.value) return; |         if (!isFieldValueEmpty(field.value)) { | ||||||
|  |           return; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         field.value = transformVariableValue(value, { targetCollectionField: collectionField }); |         field.value = transformVariableValue(value, { targetCollectionField: collectionField }); | ||||||
|       }) |       }) | ||||||
|  | |||||||
| @ -1,10 +1,14 @@ | |||||||
| import { Field } from '@formily/core'; | import { Field } from '@formily/core'; | ||||||
| import { useField, useFieldSchema, useForm } from '@formily/react'; | import { useField, useFieldSchema, useForm } from '@formily/react'; | ||||||
| import { useEffect } from 'react'; | import { nextTick } from '@nocobase/utils/client'; | ||||||
|  | import _ from 'lodash'; | ||||||
|  | import { useEffect, useRef } from 'react'; | ||||||
| import { useCollection, useCollectionManager } from '../../../../collection-manager'; | import { useCollection, useCollectionManager } from '../../../../collection-manager'; | ||||||
|  | import { useFlag } from '../../../../flag-provider'; | ||||||
| import { useVariables } from '../../../../variables'; | import { useVariables } from '../../../../variables'; | ||||||
| import { transformVariableValue } from '../../../../variables/utils/transformVariableValue'; | import { transformVariableValue } from '../../../../variables/utils/transformVariableValue'; | ||||||
| import { useSubFormValue } from '../../association-field/hooks'; | import { useSubFormValue } from '../../association-field/hooks'; | ||||||
|  | import { isDisplayField } from '../utils'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * 用于懒加载 Form 区块中只用于展示的关联字段的值 |  * 用于懒加载 Form 区块中只用于展示的关联字段的值 | ||||||
| @ -20,14 +24,29 @@ const useLazyLoadDisplayAssociationFieldsOfForm = () => { | |||||||
|   const variables = useVariables(); |   const variables = useVariables(); | ||||||
|   const field = useField<Field>(); |   const field = useField<Field>(); | ||||||
|   const { formValue: subFormValue } = useSubFormValue(); |   const { formValue: subFormValue } = useSubFormValue(); | ||||||
|  |   const { isInSubForm, isInSubTable } = useFlag() || {}; | ||||||
| 
 | 
 | ||||||
|   const schemaName = fieldSchema.name.toString(); |   const schemaName = fieldSchema.name.toString(); | ||||||
|   const formValue = subFormValue || form.values; |   const formValue = isInSubForm || isInSubTable ? subFormValue : form.values; | ||||||
|  |   const collectionFieldRef = useRef(null); | ||||||
|  | 
 | ||||||
|  |   if (collectionFieldRef.current == null) { | ||||||
|  |     collectionFieldRef.current = getCollectionJoinField(`${name}.${schemaName}`); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const sourceKeyValue = | ||||||
|  |     isDisplayField(schemaName) && collectionFieldRef.current | ||||||
|  |       ? _.get(formValue, `${schemaName.split('.')[0]}.${collectionFieldRef.current.sourceKey}`) | ||||||
|  |       : undefined; | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     // 如果 schemaName 中是以 `.` 分割的,说明是一个关联字段,需要去获取关联字段的值;
 |     // 如果 schemaName 中是以 `.` 分割的,说明是一个关联字段,需要去获取关联字段的值;
 | ||||||
|     // 在数据表管理页面,也存在 `a.b` 之类的 schema name,其 collectionName 为 fields,所以在这里排除一下 `name === 'fields'` 的情况
 |     // 在数据表管理页面,也存在 `a.b` 之类的 schema name,其 collectionName 为 fields,所以在这里排除一下 `name === 'fields'` 的情况
 | ||||||
|     if (!schemaName.includes('.') || !variables || name === 'fields') { |     if (!isDisplayField(schemaName) || !variables || name === 'fields' || !collectionFieldRef.current) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (_.isEmpty(formValue)) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -37,21 +56,23 @@ const useLazyLoadDisplayAssociationFieldsOfForm = () => { | |||||||
|       collectionName: name, |       collectionName: name, | ||||||
|     }; |     }; | ||||||
|     const variableString = `{{ $nForm.${schemaName} }}`; |     const variableString = `{{ $nForm.${schemaName} }}`; | ||||||
|     const collectionField = getCollectionJoinField(`${name}.${schemaName}`); |  | ||||||
| 
 | 
 | ||||||
|     if (!collectionField) { |     // 如果关系字段的 id 为空,则说明请求的数据还没有返回,此时还不能去解析变量
 | ||||||
|       return console.error(new Error(`useLazyLoadAssociationField: ${schemaName} not found in collection ${name}`)); |     if (sourceKeyValue === undefined) { | ||||||
|  |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     variables |     variables | ||||||
|       .parseVariable(variableString, formVariable) |       .parseVariable(variableString, formVariable) | ||||||
|       .then((value) => { |       .then((value) => { | ||||||
|         field.value = transformVariableValue(value, { targetCollectionField: collectionField }); |         nextTick(() => { | ||||||
|  |           field.value = transformVariableValue(value, { targetCollectionField: collectionFieldRef.current }); | ||||||
|  |         }); | ||||||
|       }) |       }) | ||||||
|       .catch((err) => { |       .catch((err) => { | ||||||
|         console.error(err); |         console.error(err); | ||||||
|       }); |       }); | ||||||
|   }, [schemaName.includes('.') ? formValue[schemaName.split('.')[0]] : null]); |   }, [sourceKeyValue]); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export default useLazyLoadDisplayAssociationFieldsOfForm; | export default useLazyLoadDisplayAssociationFieldsOfForm; | ||||||
|  | |||||||
| @ -0,0 +1,10 @@ | |||||||
|  | import _ from 'lodash'; | ||||||
|  | 
 | ||||||
|  | export const isFieldValueEmpty = (value) => { | ||||||
|  |   value = _.isArray(value) ? _.filter(value, (v) => !_.isEmpty(v)) : value; | ||||||
|  |   return _.isEmpty(value); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const isDisplayField = (schemaName: string) => { | ||||||
|  |   return schemaName.includes('.'); | ||||||
|  | }; | ||||||
| @ -277,13 +277,6 @@ VariablesProvider.displayName = 'VariablesProvider'; | |||||||
| 
 | 
 | ||||||
| export default VariablesProvider; | export default VariablesProvider; | ||||||
| 
 | 
 | ||||||
| /** |  | ||||||
|  * 判断是否应该请求关系字段的数据。如果是 null 则可以确定后端的数据为空,此时不需要请求;如果是 undefined 则需要请求。 |  | ||||||
|  * |  | ||||||
|  * 注意:如果后端接口的这一 “规则” 发生了变更,那么可能会出现问题。 |  | ||||||
|  * @param value |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| function shouldToRequest(value) { | function shouldToRequest(value) { | ||||||
|   // fix https://nocobase.height.app/T-2502
 |   // fix https://nocobase.height.app/T-2502
 | ||||||
|   // 兼容 `对多` 和 `对一` 子表单子表格字段的情况
 |   // 兼容 `对多` 和 `对一` 子表单子表格字段的情况
 | ||||||
| @ -291,5 +284,5 @@ function shouldToRequest(value) { | |||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return value === undefined; |   return _.isEmpty(value); | ||||||
| } | } | ||||||
|  | |||||||
| @ -103,4 +103,15 @@ describe('transformVariableValue', () => { | |||||||
|       } |       } | ||||||
|     `);
 |     `);
 | ||||||
|   }); |   }); | ||||||
|  | 
 | ||||||
|  |   test('value is undefined', () => { | ||||||
|  |     const value = undefined; | ||||||
|  |     const deps = { | ||||||
|  |       targetCollectionField: { type: 'belongsToMany', uiSchema: { 'x-component': 'AssociationField' } }, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const result = transformVariableValue(value, deps as any); | ||||||
|  | 
 | ||||||
|  |     expect(result).toMatchInlineSnapshot(`undefined`); | ||||||
|  |   }); | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -14,6 +14,10 @@ interface Deps { | |||||||
| export const transformVariableValue = (value: any, deps: Deps) => { | export const transformVariableValue = (value: any, deps: Deps) => { | ||||||
|   const { targetCollectionField } = deps; |   const { targetCollectionField } = deps; | ||||||
| 
 | 
 | ||||||
|  |   if (value == null) { | ||||||
|  |     return value; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   if (!targetCollectionField) { |   if (!targetCollectionField) { | ||||||
|     return value; |     return value; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -41,3 +41,7 @@ export const hasEmptyValue = (objOrArr: object | any[]) => { | |||||||
|   } |   } | ||||||
|   return result; |   return result; | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | export const nextTick = (fn: () => void) => { | ||||||
|  |   setTimeout(fn); | ||||||
|  | }; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user