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 { useVariables } from '../../../../variables';
|
||||
import { transformVariableValue } from '../../../../variables/utils/transformVariableValue';
|
||||
import { isDisplayField, isFieldValueEmpty } from '../utils';
|
||||
|
||||
/**
|
||||
* 用于懒加载 Form 区块中正常的关系字段
|
||||
@ -34,7 +35,8 @@ const useLazyLoadAssociationFieldOfForm = () => {
|
||||
if (
|
||||
isInAssignFieldValues ||
|
||||
_.isEmpty(cloneRecord) ||
|
||||
(formBlockType === 'create' && !isInSubForm && !isInSubTable)
|
||||
(formBlockType === 'create' && !isInSubForm && !isInSubTable) ||
|
||||
isDisplayField(schemaName)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@ -45,7 +47,7 @@ const useLazyLoadAssociationFieldOfForm = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!variables || record[schemaName] != null) {
|
||||
if (!variables || !isFieldValueEmpty(_.get(record, schemaName))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -67,7 +69,9 @@ const useLazyLoadAssociationFieldOfForm = () => {
|
||||
// 3. 所以,当 `变量预加载` 的请求晚于编辑表单的请求时,就会造成这个问题;
|
||||
// 更优的解决方案是:在 `变量预加载` 中也加上子表单中的关系字段路径,并删除编辑表单请求数据的逻辑(因为没必要了)。
|
||||
// 但是这样改动较大,可以等之后 e2e 测试较完备后再处理。
|
||||
if (field.value) return;
|
||||
if (!isFieldValueEmpty(field.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
field.value = transformVariableValue(value, { targetCollectionField: collectionField });
|
||||
})
|
||||
|
@ -1,10 +1,14 @@
|
||||
import { Field } from '@formily/core';
|
||||
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 { useFlag } from '../../../../flag-provider';
|
||||
import { useVariables } from '../../../../variables';
|
||||
import { transformVariableValue } from '../../../../variables/utils/transformVariableValue';
|
||||
import { useSubFormValue } from '../../association-field/hooks';
|
||||
import { isDisplayField } from '../utils';
|
||||
|
||||
/**
|
||||
* 用于懒加载 Form 区块中只用于展示的关联字段的值
|
||||
@ -20,14 +24,29 @@ const useLazyLoadDisplayAssociationFieldsOfForm = () => {
|
||||
const variables = useVariables();
|
||||
const field = useField<Field>();
|
||||
const { formValue: subFormValue } = useSubFormValue();
|
||||
const { isInSubForm, isInSubTable } = useFlag() || {};
|
||||
|
||||
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(() => {
|
||||
// 如果 schemaName 中是以 `.` 分割的,说明是一个关联字段,需要去获取关联字段的值;
|
||||
// 在数据表管理页面,也存在 `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;
|
||||
}
|
||||
|
||||
@ -37,21 +56,23 @@ const useLazyLoadDisplayAssociationFieldsOfForm = () => {
|
||||
collectionName: name,
|
||||
};
|
||||
const variableString = `{{ $nForm.${schemaName} }}`;
|
||||
const collectionField = getCollectionJoinField(`${name}.${schemaName}`);
|
||||
|
||||
if (!collectionField) {
|
||||
return console.error(new Error(`useLazyLoadAssociationField: ${schemaName} not found in collection ${name}`));
|
||||
// 如果关系字段的 id 为空,则说明请求的数据还没有返回,此时还不能去解析变量
|
||||
if (sourceKeyValue === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
variables
|
||||
.parseVariable(variableString, formVariable)
|
||||
.then((value) => {
|
||||
field.value = transformVariableValue(value, { targetCollectionField: collectionField });
|
||||
nextTick(() => {
|
||||
field.value = transformVariableValue(value, { targetCollectionField: collectionFieldRef.current });
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
}, [schemaName.includes('.') ? formValue[schemaName.split('.')[0]] : null]);
|
||||
}, [sourceKeyValue]);
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 判断是否应该请求关系字段的数据。如果是 null 则可以确定后端的数据为空,此时不需要请求;如果是 undefined 则需要请求。
|
||||
*
|
||||
* 注意:如果后端接口的这一 “规则” 发生了变更,那么可能会出现问题。
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
function shouldToRequest(value) {
|
||||
// fix https://nocobase.height.app/T-2502
|
||||
// 兼容 `对多` 和 `对一` 子表单子表格字段的情况
|
||||
@ -291,5 +284,5 @@ function shouldToRequest(value) {
|
||||
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) => {
|
||||
const { targetCollectionField } = deps;
|
||||
|
||||
if (value == null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (!targetCollectionField) {
|
||||
return value;
|
||||
}
|
||||
|
@ -41,3 +41,7 @@ export const hasEmptyValue = (objOrArr: object | any[]) => {
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export const nextTick = (fn: () => void) => {
|
||||
setTimeout(fn);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user