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:
被雨水过滤的空气-Rain 2023-11-14 14:15:47 +08:00 committed by GitHub
parent 887ddf0ed1
commit c25f51d99b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 66 additions and 19 deletions

View File

@ -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 });
}) })

View File

@ -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;

View File

@ -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('.');
};

View File

@ -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);
} }

View File

@ -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`);
});
}); });

View File

@ -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;
} }

View File

@ -41,3 +41,7 @@ export const hasEmptyValue = (objOrArr: object | any[]) => {
} }
return result; return result;
}; };
export const nextTick = (fn: () => void) => {
setTimeout(fn);
};