提交数据动作如何把弹窗内的数据完全返回

场景介绍

  1. 表格行的操作列有一个打开弹窗的动作
  2. 弹窗内为表格行数据的表单,表单内有一个o2m字段,展示了除关联关系字段(大部分场景为id)外的其他字段
  3. 弹窗底部动作区域有一个提交数据的客户端动作,该动作会将弹窗内表单的数据回写到表格行的数据上
场景截图

提交数据动作如何把弹窗内的数据完全返回
提交数据动作如何把弹窗内的数据完全返回

问题现象

点击提交数据的客户端动作,会将数据回写到表格行的数据上,但是表格行拿到的o2m字段的数据只有id字段,o2m字段的编码和名称并不会提交到表格行,o2m字段默认提交规则是只会提交关联关系字段(大部分场景为id)的数据

解决方案

该方案适合5.x版本,4.x版本新建的字段组件无法自动生成属性面板,建议拿下面的组件在SPI加上model和name注册实现

  1. 自定义o2m字段所在的组件,m2m字段或者其他类似问题的组件也是如下面组件一样覆写submit方法即可
    import {
    BaseFieldWidget,
    FormO2MTableFieldWidget,
    ModelFieldType,
    SPI,
    SubmitRelationValue,
    SubmitValue,
    ViewType
    } from '@kunlun/dependencies';
    @SPI.ClassFactory(
    BaseFieldWidget.Token({
    viewType: ViewType.Form,
    ttype: ModelFieldType.OneToMany,
    widget: 'SubmitAllDataO2MTable'
    })
    )
    export class MyFormO2MTableFieldWidget extends FormO2MTableFieldWidget {
    public async submit(submitValue: SubmitValue): Promise<Record<string, unknown> | SubmitRelationValue | undefined> {
    return { [this.itemName]: this.value };
    }
    }
  2. 在界面设计器的组件功能内新增对应业务类型的自定义组件,组件内的元件api名称填写上面组件的名称SubmitAllDataO2MTable
  3. 在界面设计器的设计页面切换o2m字段组件为SubmitAllDataO2MTable

参考文档

Oinone社区 作者:nation原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/14187.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
nation的头像nation数式员工
上一篇 2024年6月27日
下一篇 2024年6月28日

相关推荐

  • 如何自定义点击导出动作绑定指定模板

    介绍 平台默认的导出会打开弹窗,然后在弹窗内的视图选择是用模板方式导出还是选字段导出,但是有时候有部分场景希望点击导出动作后直接进入导出流程,导出指定的某个模板,我们可以通过覆写打开弹窗的动作来实现该功能。 本文档参考了 表格页自定义按钮如何获取搜索区域的查询条件 代码示例 以下代码大部分场景只需要修改其中excelTplName更换模板即可,另外如何想增加复用性,还可以将该属性改为从元数据的配置中获取。 import { ActionType, BaseActionWidget, BaseElementListViewWidget, BooleanHelper, ClickResult, Condition, ExcelExportTask, FILE_MODULE_NAME, getSessionPath, GraphqlHelper, http, IQueryPageResult, ISort, queryDslWidget, ReturnPromise, RuntimeServerAction, ServerActionWidget, SPI, SubmitValue, SYSTEM_MODULE_NAME, translateValueByKey, UrlHelper, ViewActionTarget, Widget } from '@kunlun/dependencies'; import { OioNotification } from '@kunlun/vue-ui-antd'; @SPI.ClassFactory( BaseActionWidget.Token({ actionType: [ActionType.View], target: [ViewActionTarget.Dialog], model: 'ys0328.k2.Model0000000453', name: 'internalGotoListExportDialog' }) ) export class DemoExportActionWidget extends ServerActionWidget { /** * excel导出模板名称 * @protected */ protected excelTplName = '演示抽屉跳转链接导出'; /** * 导出任务的模型编码 * @protected */ protected exportTaskModel = 'excelExportTask'; /** * 导出任务的方法 * @protected */ protected exportTaskFun = 'createExportTask'; /** * * 是否是同步导出 */ @Widget.Reactive() protected get syncExport() { return BooleanHelper.isTrue(this.getDsl().sync) || !true; } protected async executeAction(action: RuntimeServerAction, parameters: SubmitValue): Promise<ClickResult> { const workbookId = await this.getWorkbookId(); if (!workbookId) { return false; } let task = { workbookDefinition: { id: workbookId } } as ExcelExportTask; // 从平台内置的方法获取搜索区域的条件 const { condition } = this.getSearchRsqlAndQueryParams(); // 排序规则 let sortList = [] as ISort[]; const baseViewWidget = Widget.select(this.rootHandle); const listViewWidget = queryDslWidget(baseViewWidget?.getChildrenInstance(), BaseElementListViewWidget); if (listViewWidget) { sortList = listViewWidget.sortList; } return this.export(task, condition, sortList); } protected getUploadBodyGql(id: string, condition: string | Condition, sortList:…

    2024年10月9日
    1.8K00
  • 如何编写自定义字段组件的校验逻辑

    介绍 自定义字段组件的时候,我们可能会遇到有复杂校验规则或者业务上特殊的校验提示信息的场景,这时候可以通过覆写字段的校验方法validator来实现。 示例代码 import { SPI, ValidatorInfo, FormStringFieldWidget, isEmptyValue, isValidatorSuccess, FormFieldWidget, ViewType, ModelFieldType } from '@kunlun/dependencies' @SPI.ClassFactory(FormFieldWidget.Token({ viewType: [ViewType.Form], ttype: ModelFieldType.String, widget: 'DemoPhone' })) export class DemoFormPhoneFieldWidget extends FormStringFieldWidget { // 字段校验方法 public async validator(): Promise<ValidatorInfo> { // 建议先调用平台内置的通用校验逻辑 const res = await super.validator(); if (!isValidatorSuccess(res)) { // 校验失败直接返回 return res; } // 编写自有校验逻辑 if (!isEmptyValue(this.value) && !/^1[3456789]\d{9}$/.test(this.value as string)) { // 通过内置的validatorError方法提示校验提示信息 return this.validatorError('手机号格式错误'); } // 无异常,用内置的validatorSuccess返回校验通过的信息 return this.validatorSuccess(); } } 扩展学习 自定义字段组件如何处理vue组件内的表单校验

    2024年8月23日
    1.9K00
  • 自定义字段的数据联动

    某种情况下,开发人员期望自定以的字段发生变化后,需要修改其他的字段,这篇文章从两个维度来讲解如果处理数据的联动 界面设计器配置 1: 在界面设计器页面中的的组件区域找到自定义的字段,设计元件 2: 在模型区域,搜索提交方式,如果找到了,就把该字段拖拽进来, 如果找不到,就在元件中的组件区域,拖拽一个文本字段,按照下面的配置进行配置,然后保存 图一是找到了对应的字段图二是找不到对应的字段 【图一】 【图二】 图二的字段编码必须是constructDataTrigger 3: 从模型区搜索联动函数,将其拖拽进来 3: 从模型区搜索提交数据,将其拖拽进来4: 从模型区搜索提交字段,将其拖拽进来 5: 发布 (记得刷新页面哦) 最后再到对应的设计器页面,选中该字段,进行配置 提交方式为blur或者change , 需要开发者手动调用该方法 this.blur()或者this.change(value) // 字段对应的ts文件 class MyField extends FormFieldWidget { onChangeValue(val) { // this.change(val) // this.blur() } } 联动函数就是要调用的后端函数 提交数据分为:变更字段 -> 发生变化后的字段当前视图字段 -> 当前视图所有的字段指定字段 -> 指定字段,如果配置的指定字段,那么提交字段的配置就要输入对应的字段 代码配置 平台也支持通过代码的方式修改字段 // 字段对应的ts文件 class MyField extends FormFieldWidget { onChangeValue(val) { // 修改字段本身的值 this.change(val) // 修改其他字段的值 this.formData.otherField = 'value' this.reloadFormData$.subject.next(true); } }

    2023年11月9日
    2.1K00
  • 「前端」动作API

    概述 在 oinone 前端平台中,提供了四种动作 跳转动作(页面跳转、打开弹窗、抽屉) 服务端动作(调用接口) 客户端动作(返回上一页、关闭弹窗等) 链接动作(打开执行的链接) 快速开始 // 基础使用示例 import { executeViewAction, executeServerAction, executeUrlAction } from '@kunlun/dependencies'; // 示例 1: 基础页面跳转(去创建页面) executeViewAction(action); // 示例 2: 带参数的页面跳转(查询ID为123的数据),去编辑、详情页 executeViewAction(action, undefined, undefined, { id: '123' }); // 示例 3: 页面跳转的参数,用最新的,防止当前页面的参数被带到下一个页面 executeViewAction(action, undefined, undefined, { id: '123' , preserveParameter: true}); // 示例 4: 调用服务端接口 const params = { id: 'xxx', name: 'xxx' }; await executeServerAction(action, params); await executeServerAction(action, params, { maxDepth: 2 }); // 接口数据返回的数据层级是3层 -> 从0开始计算, 默认是2层 // 执行链接动作 executeUrlAction(action); API 详解 executeViewAction 参数名 描述 类型 必填 默认值 — action 视图动作 RuntimeViewAction true router 路由实例 Router false undefined matched 路由匹配参数 Matched false undefined extra 扩展参数 object false {} target 规定在何处打开被链接文档(可参考 a 标签的 target) string false undefined executeServerAction 参数名 描述 类型 必填 默认值 ​action 服务端动作 RuntimeServerAction true param 传递给后端的参数 object true context 配置接口返回的数据层级(默认是两层) {maxDepth: number} false executeUrlAction 参数名 描述 类型 必填 默认值 ​action 链接动作 IURLAction true

    2025年3月21日
    1.2K00
  • 从一个方法开始:浅析页面渲染流程

    渲染前的准备 渲染前的准备,在 Vue 渲染框架下,会先安装所有所支持的默认组件,比如 Mask,Header 等,这些组件支持 XML 默认模版的 Vue 框架下的渲染,详情可见 main.ts 中,maskInstall 与 install,这两个函数将平台内部支持的组件进行了注册,随后将整个 Vue 挂载为运行时 App,随后进行初始化。 渲染的起步 OioProvider 方法是整个应用的入口,我们忽略掉一些配置方法,将注意力集中到 initializeServices 从名称中我们可以看出来内部保存的都是初始化服务,其中提供了渲染服务等,我们当前使用的是 Vue 框架,所以当前其渲染的 Root 节点为 Vue, 以此,我们视野可以暂时转移到 admin-base中的 Root.vue以及 RootWidget上, 其实现了整个 Vue 框架下的 Root 节点如何渲染,其中定义了多个 widget,比如登陆页,首页,忘记密码已经重置密码等页面, 在本文中我们着重关注渲染首页的能力,RootWidget将 DefaultMetadataMainViewWidget作为渲染 Props中的 page即首页提供给下层组件使用, 渐入佳境 DefaultMetadataMainViewWidget从名称中可以看到,其为元数据主视图,主要做两件事,1:提供 Mask 的渲染2:提供元数据上下文初始化 该组件主要通过观察路由变化触发上面两个动作,当路由发生变化,该组件 reloadPage将被调用,reloadPage方法通过组装路由参数构成一个唯一 key 向后段查询当前路由所对应的渲染信息, 随后将获取到的信息进行处理,初始化,即 元数据上下文初始化,在初始化后,会将获取到的数据注入到 MetadataViewWidget中, Mask 的渲染 关于 Mask 的渲染,在获取到数据后,将生成 maskTemplate,并将其赋值, DefaultMetadataMainView.vue文件将渲染该模板,并渲染到页面中 数据的变更 当上面两件任务完成后,将开始主视图的渲染,上文提到,DefaultMetadataMainViewWidget只负责 mask 的渲染和上下文的初始化,所以 DefaultMetadataMainViewWidget通过触发事件的方式来实现主视图的渲染, DefaultMetadataMainViewWidget将必要信息作为事件参数触发,MultiTabsContainerWidget接收到 reloadMainViewCallChaining事件后,开启主视图渲染, MultiTabsContainerWidget会刷新运行时上下文,即 refreshRuntimeContext,该方法将尝试查询并通过 createOrUpdateEnterTab方法创建 Tab 页,createOrUpdateEnterTab最终生成一个 MultiTabItem格式的对象,该对象描述了 Tab 的相关信息,随后调用 createTabContainerWidget创建 tab 的容器即新建了一个 MultiTabContainerWidget组件即单个 tab 的容器,随后调用 setActiveTabItem, 并获取其绑定的 Vue 组件,并将其组件放置在 KeepAlive内部,触发更新, 主视图的渲染 MultiTabContainerWidget继承自MetadataViewWidget,当 MetadataViewWidget数据发生变更, 其绑定的 Vue 组件将解析 viewTemplate, 获取到与该模板 dslNodeType想匹配的 Vue 组件,当前例子中为 View.vue,随后 View.vue开始渲染,View.vue文件只是一个纯粹的容器,当 View.vue被挂载时,其内部的 template属性包含了整个页面的描述信息,View.vue需要做的就是将这个 template翻译并渲染成 DOM 展现在浏览器上, 渲染整个页面 当 View.vue被挂载时,其内部的 template属性包含了整个页面的描述信息,View.vue主要做了两个事情,一:将 template 中的 widget转换为组件,二:根据当前的 template信息生成 slot信息, const currentSlots = computed<Slots | undefined>( () => DslRender.fetchVNodeSlots(props.dslDefinition) || (Object.keys(context.slots).length ? context.slots : undefined) ); const renderWidget = createCustomWidget(InternalWidget.View, { …context.attrs, type: props.type || viewType.value, template: props.dslDefinition, metadataHandle: props.metadataHandle || metadataHandle.value, rootHandle: props.rootHandle || rootHandle.value, parentHandle: props.parentHandle || parentHandle.value, slotName: props.slotName, inline: inlineProp } as ViewWidgetProps); 生成这两部分信息后,View.vue会将这两部分挂载到页面上,这两部分从代码中可以看出,主要靠 fetchVNodeSlots,createCustomWidget两个函数, export function createCustomWidget( widget: string, props: CustomWidgetProps ): RenderWidget | undefined public static fetchVNodeSlots(dsl: DslDefinition | undefined, supportedSlotNames?: string[]):…

    2025年3月19日
    77700

Leave a Reply

登录后才能评论