mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:48:13 +08:00
feat: reload 支持动态目标, 解决目标在循环中场景 (#6372)
This commit is contained in:
parent
e15892f8dd
commit
b415a1f0f7
@ -485,3 +485,160 @@ amis 会将返回的 `data` 写入表单数据域,因此下面的 `static` 组
|
||||
上例中点击按钮会刷新`target1`和`target2`组件。
|
||||
|
||||
事实上,**组件间联动也可以实现上述任意的 [基本联动效果](./linkage#%E5%9F%BA%E6%9C%AC%E8%81%94%E5%8A%A8)(显隐联动、接口联动等其他联动)。**
|
||||
|
||||
### 动态目标
|
||||
|
||||
> 2.9.0 及以上版本
|
||||
|
||||
刷新目标支持表达式,比如目标可以配置成 `form-${ xxx ? '1' : '2'}`。
|
||||
|
||||
```schema: scope="body"
|
||||
[
|
||||
{
|
||||
"title": "查询条件",
|
||||
"type": "form",
|
||||
"target": "my_crud_${searchTarget}",
|
||||
"body": [
|
||||
{
|
||||
"type": "radios",
|
||||
"name": "searchTarget",
|
||||
"label": "选择目标",
|
||||
value: 1,
|
||||
options: [
|
||||
{
|
||||
value: 1,
|
||||
label: "列表 1"
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: "列表 2"
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "keywords",
|
||||
"label": "关键字:"
|
||||
}
|
||||
],
|
||||
"submitText": "搜索"
|
||||
},
|
||||
{
|
||||
"type": "crud",
|
||||
"api": "/api/mock2/sample",
|
||||
"name": "my_crud_1",
|
||||
"title": "列表 1",
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"label": "ID"
|
||||
},
|
||||
{
|
||||
"name": "engine",
|
||||
"label": "Rendering engine"
|
||||
},
|
||||
{
|
||||
"name": "browser",
|
||||
"label": "Browser"
|
||||
},
|
||||
{
|
||||
"name": "platform",
|
||||
"label": "Platform(s)"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"label": "Engine version"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"type": "crud",
|
||||
"api": "/api/mock2/sample",
|
||||
"name": "my_crud_2",
|
||||
"title": "列表 2",
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"label": "ID"
|
||||
},
|
||||
{
|
||||
"name": "engine",
|
||||
"label": "Rendering engine"
|
||||
},
|
||||
{
|
||||
"name": "browser",
|
||||
"label": "Browser"
|
||||
},
|
||||
{
|
||||
"name": "platform",
|
||||
"label": "Platform(s)"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"label": "Engine version"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
如果目标组件在列表中,则实际渲染的时候会存在多份,通过某个固定名字没办法找到对应的组件。比如某个 crud 里面,某列设置的是一个 service,通过 service 拉取数据。如果想在操作栏里面某个操作完后刷新对应的 service,通过固定的名字是没办法找到对应的 service 的。所以名字 `name` 也支持动态名字。如: `my-service-${id}` 把行数据中动态的 id 设置进去。
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
type: 'crud',
|
||||
api: "/api/mock2/sample",
|
||||
columns: [
|
||||
{
|
||||
name: 'id',
|
||||
label: 'ID'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'service',
|
||||
api: "/api/mock2/sample/${id}",
|
||||
label: 'Service',
|
||||
name: "my-servce-${id}",
|
||||
body: [
|
||||
{
|
||||
type: "tpl",
|
||||
tpl: "${browser}"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'operation',
|
||||
label: '操作',
|
||||
buttons: [
|
||||
{
|
||||
type: "button",
|
||||
label: "编辑",
|
||||
actionType: "dialog",
|
||||
dialog: {
|
||||
"title": "编辑",
|
||||
|
||||
body: [
|
||||
{
|
||||
type: 'form',
|
||||
api: "/api/mock2/sample/${id}",
|
||||
body: [
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'browser',
|
||||
label: 'Browser'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
reload: "my-servce-${id}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
> 这个例子 api 是 mock 的,所以修改后刷新没效果。
|
||||
|
@ -201,7 +201,7 @@ export class RootRenderer extends React.Component<RootRendererProps> {
|
||||
action.reload &&
|
||||
this.reloadTarget(
|
||||
delegate || this.context,
|
||||
action.reload,
|
||||
filter(action.reload, ctx),
|
||||
store.data
|
||||
);
|
||||
})
|
||||
|
@ -21,6 +21,7 @@ import {
|
||||
} from './utils/helper';
|
||||
import {RendererData, ActionObject} from './types';
|
||||
import {isPureVariable} from './utils/isPureVariable';
|
||||
import {filter} from './utils';
|
||||
|
||||
export interface ScopedComponentType extends React.Component<RendererProps> {
|
||||
focus?: () => void;
|
||||
@ -36,11 +37,7 @@ export interface ScopedComponentType extends React.Component<RendererProps> {
|
||||
ctx?: RendererData
|
||||
) => void;
|
||||
context: any;
|
||||
setData?: (
|
||||
value?: object,
|
||||
replace?: boolean,
|
||||
index?: number
|
||||
) => void;
|
||||
setData?: (value?: object, replace?: boolean, index?: number) => void;
|
||||
}
|
||||
|
||||
export interface IScopedContext {
|
||||
@ -109,7 +106,8 @@ function createScopedTools(
|
||||
const resolved = find(
|
||||
components,
|
||||
component =>
|
||||
component.props.name === name || component.props.id === name
|
||||
filter(component.props.name, component.props.data) === name ||
|
||||
component.props.id === name
|
||||
);
|
||||
return resolved || (parent && parent.getComponentByName(name));
|
||||
},
|
||||
|
@ -1091,10 +1091,11 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
dispatchEvent('validateSucc', this.props.data);
|
||||
|
||||
if (target) {
|
||||
this.submitToTarget(target, values);
|
||||
this.submitToTarget(filter(target, values), values);
|
||||
dispatchEvent('submitSucc', createObject(this.props.data, values));
|
||||
} else if (action.actionType === 'reload') {
|
||||
action.target && this.reloadTarget(action.target, values);
|
||||
action.target &&
|
||||
this.reloadTarget(filter(action.target, values), values);
|
||||
} else if (action.actionType === 'dialog') {
|
||||
store.openDialog(data);
|
||||
} else if (action.actionType === 'drawer') {
|
||||
@ -1193,7 +1194,10 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
);
|
||||
finalRedirect && env.jumpTo(finalRedirect, action);
|
||||
} else if (action.reload || reload) {
|
||||
this.reloadTarget(action.reload || reload!, store.data);
|
||||
this.reloadTarget(
|
||||
filter(action.reload || reload!, store.data),
|
||||
store.data
|
||||
);
|
||||
}
|
||||
|
||||
action.close && this.closeTarget(action.close);
|
||||
@ -1256,7 +1260,8 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
action.redirect && filter(action.redirect, store.data);
|
||||
redirect && env.jumpTo(redirect, action);
|
||||
|
||||
action.reload && this.reloadTarget(action.reload, store.data);
|
||||
action.reload &&
|
||||
this.reloadTarget(filter(action.reload, store.data), store.data);
|
||||
action.close && this.closeTarget(action.close);
|
||||
})
|
||||
.catch(e => {
|
||||
@ -1268,7 +1273,7 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
} else if (action.actionType === 'reload') {
|
||||
store.setCurrentAction(action);
|
||||
if (action.target) {
|
||||
this.reloadTarget(action.target, data);
|
||||
this.reloadTarget(filter(action.target, data), data);
|
||||
} else {
|
||||
this.receive(data);
|
||||
}
|
||||
|
@ -680,7 +680,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
const redirect = action.redirect && filter(action.redirect, data);
|
||||
redirect && !action.blank && env.jumpTo(redirect, action);
|
||||
action.reload
|
||||
? this.reloadTarget(action.reload, data)
|
||||
? this.reloadTarget(filter(action.reload, data), data)
|
||||
: redirect
|
||||
? null
|
||||
: this.search(undefined, undefined, true, true);
|
||||
@ -779,7 +779,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
}
|
||||
|
||||
action.reload
|
||||
? this.reloadTarget(action.reload, data)
|
||||
? this.reloadTarget(filter(action.reload, data), data)
|
||||
: this.search(
|
||||
{[pageField || 'page']: 1},
|
||||
undefined,
|
||||
@ -1038,7 +1038,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
|
||||
const reload = action.reload ?? dialogAction.reload;
|
||||
if (reload) {
|
||||
this.reloadTarget(reload, ctx);
|
||||
this.reloadTarget(filter(reload, ctx), ctx);
|
||||
}
|
||||
|
||||
let redirect = action.redirect ?? dialogAction.redirect;
|
||||
@ -1279,7 +1279,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
.then(() => {
|
||||
const finalReload = options?.reload ?? reload;
|
||||
finalReload
|
||||
? this.reloadTarget(finalReload, data)
|
||||
? this.reloadTarget(filter(finalReload, data), data)
|
||||
: this.search(undefined, undefined, true, true);
|
||||
})
|
||||
.catch(() => {});
|
||||
@ -1301,7 +1301,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
.then(() => {
|
||||
const finalReload = options?.reload ?? reload;
|
||||
finalReload
|
||||
? this.reloadTarget(finalReload, data)
|
||||
? this.reloadTarget(filter(finalReload, data), data)
|
||||
: this.search(undefined, undefined, true, true);
|
||||
})
|
||||
.catch(() => {
|
||||
@ -1406,7 +1406,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
store
|
||||
.saveRemote(saveOrderApi, model)
|
||||
.then(() => {
|
||||
reload && this.reloadTarget(reload, model);
|
||||
reload && this.reloadTarget(filter(reload, model), model);
|
||||
this.search(undefined, undefined, true, true);
|
||||
})
|
||||
.catch(() => {});
|
||||
|
@ -658,7 +658,7 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
|
||||
errorMessage: messages && messages.saveSuccess
|
||||
})
|
||||
.then(() => {
|
||||
reload && this.reloadTarget(reload, data);
|
||||
reload && this.reloadTarget(filter(reload, data), data);
|
||||
this.getData(undefined, undefined, true, true);
|
||||
})
|
||||
.catch(() => {});
|
||||
@ -678,7 +678,7 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
|
||||
store
|
||||
.saveRemote(quickSaveItemApi, sendData)
|
||||
.then(() => {
|
||||
reload && this.reloadTarget(reload, data);
|
||||
reload && this.reloadTarget(filter(reload, data), data);
|
||||
this.getData(undefined, undefined, true, true);
|
||||
})
|
||||
.catch(() => {
|
||||
@ -784,7 +784,7 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
|
||||
store
|
||||
.saveRemote(saveOrderApi, model)
|
||||
.then(() => {
|
||||
reload && this.reloadTarget(reload, model);
|
||||
reload && this.reloadTarget(filter(reload, model), model);
|
||||
this.getData(undefined, undefined, true, true);
|
||||
})
|
||||
.catch(() => {});
|
||||
|
@ -891,7 +891,8 @@ export class DialogRenderer extends Dialog {
|
||||
const reidrect =
|
||||
action.redirect && filter(action.redirect, store.data);
|
||||
reidrect && env.jumpTo(reidrect, action);
|
||||
action.reload && this.reloadTarget(action.reload, store.data);
|
||||
action.reload &&
|
||||
this.reloadTarget(filter(action.reload, store.data), store.data);
|
||||
if (action.close) {
|
||||
this.handleSelfClose();
|
||||
this.closeTarget(action.close);
|
||||
|
@ -852,7 +852,8 @@ export class DrawerRenderer extends Drawer {
|
||||
const redirect =
|
||||
action.redirect && filter(action.redirect, store.data);
|
||||
redirect && env.jumpTo(redirect, action);
|
||||
action.reload && this.reloadTarget(action.reload, store.data);
|
||||
action.reload &&
|
||||
this.reloadTarget(filter(action.reload, store.data), store.data);
|
||||
if (action.close) {
|
||||
this.handleSelfClose();
|
||||
this.closeTarget(action.close);
|
||||
|
@ -508,7 +508,8 @@ export default class Page extends React.Component<PageProps> {
|
||||
const redirect =
|
||||
action.redirect && filter(action.redirect, store.data);
|
||||
redirect && env.jumpTo(redirect, action);
|
||||
action.reload && this.reloadTarget(action.reload, store.data);
|
||||
action.reload &&
|
||||
this.reloadTarget(filter(action.reload, store.data), store.data);
|
||||
})
|
||||
.catch(e => {
|
||||
if (throwErrors || action.countDown) {
|
||||
|
@ -47,7 +47,7 @@ export const eventTypes = [
|
||||
'onWsFetched'
|
||||
] as const;
|
||||
|
||||
export type ProviderEventType = typeof eventTypes[number];
|
||||
export type ProviderEventType = (typeof eventTypes)[number];
|
||||
|
||||
export type DataProviderCollection = Partial<
|
||||
Record<ProviderEventType, DataProvider>
|
||||
@ -684,7 +684,8 @@ export default class Service extends React.Component<ServiceProps> {
|
||||
const redirect =
|
||||
action.redirect && filter(action.redirect, store.data);
|
||||
redirect && env.jumpTo(redirect, action);
|
||||
action.reload && this.reloadTarget(action.reload, store.data);
|
||||
action.reload &&
|
||||
this.reloadTarget(filter(action.reload, store.data), store.data);
|
||||
})
|
||||
.catch(e => {
|
||||
if (throwErrors || action.countDown) {
|
||||
|
@ -910,7 +910,7 @@ export default class Table2 extends React.Component<Table2Props, object> {
|
||||
errorMessage: messages && messages.saveSuccess
|
||||
})
|
||||
.then(() => {
|
||||
reload && this.reloadTarget(reload, data);
|
||||
reload && this.reloadTarget(filter(reload, data), data);
|
||||
})
|
||||
.catch(() => {});
|
||||
} else {
|
||||
@ -929,7 +929,7 @@ export default class Table2 extends React.Component<Table2Props, object> {
|
||||
store
|
||||
.saveRemote(quickSaveItemApi, sendData)
|
||||
.then(() => {
|
||||
reload && this.reloadTarget(reload, data);
|
||||
reload && this.reloadTarget(filter(reload, data), data);
|
||||
})
|
||||
.catch(() => {
|
||||
options?.resetOnFailed && this.reset();
|
||||
|
@ -600,11 +600,12 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
||||
action.redirect && filter(action.redirect, store.data);
|
||||
reidrect && env.jumpTo(reidrect, action);
|
||||
|
||||
action.reload && this.reloadTarget(action.reload, store.data);
|
||||
action.reload &&
|
||||
this.reloadTarget(filter(action.reload, store.data), store.data);
|
||||
})
|
||||
.catch(reason => {});
|
||||
} else if (action.actionType === 'reload') {
|
||||
action.target && this.reloadTarget(action.target, data);
|
||||
action.target && this.reloadTarget(filter(action.target, data), data);
|
||||
} else if (action.actionType === 'goto-step') {
|
||||
const targetStep = (data as any).step;
|
||||
|
||||
@ -708,7 +709,7 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
||||
|
||||
// 最后一步
|
||||
if (target) {
|
||||
this.submitToTarget(target, store.data);
|
||||
this.submitToTarget(filter(target, store.data), store.data);
|
||||
this.setState({completeStep: steps.length});
|
||||
} else if (action.api || step.api || api) {
|
||||
let finnalAsyncApi = action.asyncApi || step.asyncApi || asyncApi;
|
||||
@ -797,7 +798,7 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
||||
env.jumpTo(finalRedirect, action);
|
||||
} else if (action.reload || step.reload || reload) {
|
||||
this.reloadTarget(
|
||||
action.reload || step.reload || reload!,
|
||||
filter(action.reload || step.reload || reload!, store.data),
|
||||
store.data
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user