antd form表单数据回显操作


Posted in Javascript onNovember 02, 2020

index页面有一个表格,有一个新增按钮,点击新增按钮或表格编辑弹出表单模块,如果是编辑,会回显对应的表格中的数据

//index页面
import React from 'react'
import { Table, Button, message, Input, Select, Modal, } from 'antd';
const Option = Select.Option;
import AddOrEdit from './AddOrEdit '
class List extends React.Component {
 constructor(props) {
 super(props);
 }
 state = {
 id: "",
 selectOpt: {
  getPopupContainer: () => {
  return this.refs.myForm
  }
 },
 tableOption: {
  //表头
  columns: [
  { title: '员工姓名', key: 'workerName', dataIndex: 'workerName' },
  { title: '员工工号', key: 'workNumber', dataIndex: 'workNumber' },
  {
   title: "操作", key: 'action', className: 'columnsCenter', render: (text, record) => {
   return (
    <a title="编辑" type="edit" onClick={this.addOrEditClick.bind(this, record)}>编辑</a>
   )
   }
  }
  ],
  dataSource: [], //表格总数据
  loading: false,
  scroll: { x: 1600 },
  //分页初始数据
  pagination: {
  current: 1, pageSize: 10, total: 0, showTotal: total => `共 ${total} 条`
  }
 },
 //编辑表单详细信息
 dataForm: {
  data: [],
  model: {
  id: { value: undefined },
  workerName: { value: undefined },//员工姓名
  workNumber: { value: undefined }//员工工号
  },
  param: {}
 },
 //form表单模块
 modalOption: {
  title: "新增/修改",
  visible: false,
  footer: null,
  destroyOnClose: true,
  width: 900
 },
 }
 //编辑数据回显
 addOrEditClick(record) {
 const self = this;
 let { modalOption, dataForm } = this.state;
 dataForm.param = JSON.parse(JSON.stringify(dataForm.model));
 //如果是编辑弹出表单并且数据回显,否则就是新增
 if (record.id) {
  api.get(APIS.yluAssessTarget + record.id).then(function (response) {
  const data = response.data.data;
  dataForm.param.id.value = data.id;
  //给
  dataForm.param.workerName.value = data.workerName;
  dataForm.param.workNumber.value = data.workNumber;
  modalOption.visible = true;
  self.setState({ modalOption, dataForm });
  });
 } else {
  modalOption.visible = true;
  self.setState({ modalOption });
 }
 }
 //分页
 onTableChange(pagination, filters, sorte) {
 if (pagination.current) {
  let { tableOption, searchObj } = this.state;
  tableOption.pagination.current = pagination.current;
  tableOption.pagination.pageSize = pagination.pageSize;
  this.setState({ tableOption });
 }
 this.loadTable();
 };
 /**
 * 初始化列表
 */
 loadTable() {
 let self = this, { tableOption } = this.state;
 tableOption.loading = true;
 self.setState({ tableOption });
 api.post(APIS.yluAssessTargetSearch + '?current=' + tableOption.pagination.current + '&pageSize=' + tableOption.pagination.pageSize, {
  data: {
  companyName: "查询参数"//分公司名
  }
 }).then(function (response) {
  tableOption.dataSource = response.data.data.
  tableOption.pagination.total = response.data.data.total;
 }).finally(() => {
  tableOption.loading = false;
  self.setState({ tableOption, notDataLevelGroup, searchObj });
 });
 }
 render() {
 const self = this;
 let { tableOption, modalOption, dataForm } = this.state;
 return (
  <div>
  <Button size="small" type="primary" onClick={this.addOrEditClick.bind(this, 0)} >新增</Button>
  <Table {...tableOption} bordered onChange={this.onTableChange.bind(this)} />
  <Modal {...modalOption} >
   {modalOption.visible ? <AddOrEdit {...dataForm} /> : null}
  </Modal>
  </div>

 )
 }
 componentDidMount() {
 this.loadTable();
 }
}
//form表单页,点击编辑或新增的时候会弹出,并且编辑的时候下拉框value值就为表格当前的这一条数据对应的值
//对select里面的value值用getFieldDecorator进行绑定
import React from 'react'
import { Table, Button, Select, Form, message, Row, Col, } from 'antd';
const Option = Select.Option;
class AddOrEdit extends React.Component {
 //提交保存
 handleSubmit(e) {
 e.preventDefault();
 const self = this;
 this.props.form.validateFieldsAndScroll((err, values) => {
  if (!err) {
  //提交保存
  api.post(APIS.yluAssessTarget, {
   data: {
   ...values,
   }
  }).then(res => {
   message.success(res.data.message)
  }).finally(() => {
   self.setState({ addOrEditFooterLoading: false })
  })
  }
 });
 }
 render() {
 const { workerNameList, workNumberList} = this.state;
 const { getFieldDecorator } = this.props.form;
 const reqMeg = '不能为空';
 const renderOption = (arr, code, name) => arr ? arr.map((item, index) => {
  return (<Option key={index + item[code]} value={typeof (item[code]) === 'number' ? item[code].toString() : item[code]}>{item[name]}</Option>)
 }) : null

 return (
  <Form styleName="form_box" onSubmit={this.handleSubmit.bind(this)} >
  <Col {...span24}>
   <FormItem label="员工姓名" {...formItemLayout} hasFeedback>
   {getFieldDecorator('workerName', {
    rules: [{ required: true, message: reqMeg }]
   })(<Select
    placeholder="请选择"
   >
    {renderOption(workerNameList, 'workCode', 'name')}
   </Select>)}
   </FormItem>
  </Col>
  <Col {...span24}>
   <FormItem label="员工工号" {...formItemLayout} hasFeedback>
   {getFieldDecorator('workNumber', {
    rules: [{ required: true, message: reqMeg }]
   })(<Select
    placeholder="请选择"
   >
    {renderOption(workNumberList, 'workNumber', 'name')}
   </Select>)}
   </FormItem>
  </Col>
  </Form>
 )
 }
}
export default AddOrEdit;

补充知识:Ant Design Vue 中a-upload组件通过axios实现文件列表上传与更新回显的前后端处理方案

前言

在企业应用的快速开发中,我们需要尽快的完成一些功能。如果您使用了Ant Design Vue,在进行表单的文件上传相关功能开发的时候,您肯定迫不及待地需要找到一篇包治百病的文章,正是如此,才有了该文的诞生,愿以此文解君忧。

方案设计

前端方案设计

重写a-upload的文件上传方式,使用axios来进行上传

选择一个文件后立即进行上传,前端记录上传成功后的name和uid,并构建一个File实例,用于a-upload组件的已上传文件列表的回显

提交前让文件列表转化为要后端要处理的uid列表

后端方案设计

提供一个统一上传单个文件的接口,每个文件选择后自动上传都将上传到该接口,并写入到数据库的file数据表中

对表单数据新建完成后,对上传的文件列表进行当前实体记录的绑定

对表单数据更新完成后,检测该实体记录的所有文件列表,对没有在该列表中的uid的文件列表进行删除,然后对该列表中所有的uid文件记录进行当前实体记录的绑定

新建与更新的一致性处理方案

因为更新表单在读取旧数据后,需要与新选择文件进行同样的格式化处理,这里的处理流程一样,进行回显的数据是一样的,提交表单也都是提交file表中已经存在的uid列表,所以这里的数据结构是一致的,处理起来将会更加简洁明了。

让代码说话

为了让各位看官老爷们便于理解,直接上代码,希望能将整件事说明白。

构建表单

<a-form :form="form"> 
 <a-form-item label="名称" style="margin-bottom: 0;"> 
 <a-input v-decorator="['name', {rules: [{required: true, message: '请输入名称!'}]}]" /> 
 </a-form-item>
 <a-form-item> 
 <a-upload 
 :multiple="true" 
 :fileList="downloadFiles" 
 :remove="handleDownloadFileRemove" 
 :customRequest="downloadFilesCustomRequest" 
 > 
 <a-button class="upload-btn"> <a-icon type="upload" > 相关下载 </a-button> 
 </a-upload> 
 </a-form-item>
</a-form>

编写js代码

请求后端接口的token、header以及baseUrl等我已默认您已经在axios的统一设置中已经配置好了

为了简化axios相关操作,我们将axios进行了如下封装(您也可以按此完全使用axios来直接对数据进行提交等):

const dibootApi = {
 get (url, params) { 
 return axios.get(url, { 
 params 
 }) 
 }, 
 upload(url, formData) { 
 return service({ 
 url, 
 method: 'POST', 
 data: formData 
 }) 
 }
}
export default dibootApi

我们默认为demo实体中需要上传一些文件列表

export default {
 name: 'demoForm',
 data () {
 title: '新建',    // 该表单的功能标题
 form: this.$form.createForm(this), // 表单数据初始化,没什么好说的
 model: {},    // 如果是更新表单,之前的数据放到这里,来做数据初始化显示之用
 downloadFiles: []    // 已经上传的文件列表
 },
 methods: {
 // 初始打开的表单时的处理(如果是更新表单,这里首先需要读取出相关数据)
 async open (id) { 
  if (id === undefined) { 
  // 没有id数据则认为是新建 
  this.model = {} 
  this.afterOpen() 
  } else { 
  // 否则作为更新处理 
  const res = await dibootApi.get(`/${this.name}/${id}`) 
  if (res.code === 0) { 
  this.model = res.data 
  this.title = '编辑' 
  this.afterOpen(id) 
  } else { 
  this.$notification.error({ 
   message: '获取数据失败', 
   description: res.msg 
  }) 
  } 
  } 
 },
 // 更新表单在读取数据完成后的操作
 afterOpen (id) { 
  // 获取该记录信息后,回显文件列表相关操作
  dibootApi.post(`/demo/getFiles/${id}`).then(res => { 
  if (res.code === 0){ 
   if (res.data.downloadFile !== undefined){ 
   res.data.downloadFile.forEach(data => { 
    this.downloadFiles.push(this.fileFormatter(data)) 
   }) 
   }
  } 
  }) 
 },
 // 重写a-upload的文件上传处理方式
 downloadFilesCustomRequest (data) { 
  this.saveFile(data) 
 }, 
 // 上传并保存文件
 saveFile (data){ 
  const formData = new FormData() 
  formData.append('file', data.file) 
  dibootApi.upload('/demo/upload', formData).then((res) => { 
  if (res.code === 0){ 
   let file = this.fileFormatter(res.data) 
   // 上传单个文件后,将该文件会先到a-upload组件的已上传文件列表中的操作
   this.downloadFiles.push(file) 
  } else { 
   this.$message.error(res.msg) 
  } 
  }) 
 },
 // 对上传成功返回的数据进行格式化处理,格式化a-upload能显示在已上传列表中的格式(这个格式官方文档有给出的)
 fileFormatter(data) { 
  let file = { 
  uid: data.uuid, // 文件唯一标识,建议设置为负数,防止和内部产生的 id 冲突 
  name: data.name, // 文件名 
  status: 'done', // 状态有:uploading done error removed 
  response: '{"status": "success"}', // 服务端响应内容 
  } 
  return file 
 },
 // 没错,删除某个已上传的文件的时候,就是调用的这里
 handleDownloadFileRemove (file) { 
  const index = this.downloadFiles.indexOf(file) 
  const newFileList = this.downloadFiles.slice() 
  newFileList.splice(index, 1) 
  this.downloadFiles = newFileList 
 },
 // 表单校验就靠他了,不过这里面还是可以对需要提交的一些数据做些手脚的
 validate () { 
  return new Promise((resolve, reject) => { 
  this.form.validateFields((err, fieldsValue) => { 
   if (!err) { 
   // 设置上传文件列表 
   const downloadFiles = this.downloadFiles.map(o => { 
    return o.uid 
   }) 
   const values = { 
    ...fieldsValue, 
    'downloadFiles': downloadFiles
   } 
   resolve(values) 
   } else { 
   reject(err) 
   }
  }) 
  }) 
 },
 // 表单提交的相关操作
 async onSubmit () { 
  const values = await this.validate() 
  try { 
  let result = {} 
  if (this.model.id === undefined) { 
   // 新增该记录 
   result = await this.add(values) 
  } else { 
   // 更新该记录 
   values['id'] = this.model.id 
   result = await this.update(values) 
  } 

  // 执行提交成功的一系列后续操作 
  this.submitSuccess(result) 
  } catch (e) { 
  // 执行提交失败的一系列后续操作 
  this.submitFailed(e) 
  } 
 },
 // 新增数据的操作
 async add (values) {
  ....
 },
 // 更新数据的操作
 async update (values) {
  ...
 }
 }
}

编写SpringBoot相关的接口代码

DemoController

/*** 
 * 获取文件信息列表 
 * @param id 
 * @return 
 * @throws Exception 
 */
@PostMapping("/getFiles/{id}") 
public JsonResult getFilesMap(@PathVariable("id") Serializable id) throws Exception{ 
 List<File> files = fileService.getEntityList( 
  Wrappers.<File>lambdaQuery() 
   .eq(File::getRelObjType, Demo.class.getSimpleName()) 
   .eq(File::getRelObjId, id) 
 ); 
 return new JsonResult(Status.OK, files); 
}

/*** 
 * 上传文件 
 * @param file 
 * @param request 
 * @return 
 * @throws Exception 
 */
@PostMapping("/upload") 
public JsonResult upload(@RequestParam("file") MultipartFile file) throws Exception { 
 File fileEntity = demoService.uploadFile(file); 
 return new JsonResult(Status.OK, fileEntity, "上传文件成功"); 
}

/***
* 创建成功后的相关处理
* @param entity
* @return
*/
@Override
protected String afterCreated(BaseEntity entity) throws Exception {
 DemoDTO demoDTO = (DemoDTO) entity;
 // 更新文件关联信息
 demoService.updateFiles(new ArrayList<String>(){{
 addAll(demoDTO.getDownloadFiles());
 }}, demoDTO.getId(), true);
 return null;
}

/***
* 更新成功后的相关处理
* @param entity
* @return
*/
@Override
protected String afterUpdated(BaseEntity entity) throws Exception {
 DemoDTO demoDTO = (DemoDTO) entity;
 // 更新文件关联信息
 demoService.updateFiles(new ArrayList<String>(){{
 addAll(demoDTO.getDownloadFiles());
 }}, demoDTO.getId(), false);
 return null;
}

DemoService

@Override 
public File uploadFile(MultipartFile file) { 
 if(V.isEmpty(file)){ 
 throw new BusinessException(Status.FAIL_OPERATION, "请上传图片"); 
 } 
 String fileName = file.getOriginalFilename(); 
 String ext = fileName.substring(fileName.lastIndexOf(".")+1); 
 String newFileName = S.newUuid() + "." + ext; 
 //TODO: 需要对合法的文件类型进行验证 
 if(FileHelper.isImage(ext)){ 
 throw new BusinessException(Status.FAIL_OPERATION, "请上传合法的文件类型"); 
 }; 
 
 // 说明:此处为我们的处理流程,看官们需要根据自己的需求来对文件进行保存及处理(之后我们的File组件开源之后也可以按照此处的处理)
 String filePath = FileHelper.saveFile(file, newFileName); 
 if(V.isEmpty(filePath)){ 
 throw new BusinessException(Status.FAIL_OPERATION, "图片上传失败"); 
 } 
 
 File fileEntity = new File(); 
 fileEntity.setRelObjType(Demo.class.getSimpleName()); 
 fileEntity.setFileType(ext); 
 fileEntity.setName(fileName); 
 fileEntity.setPath(filePath); 
 String link = "/file/download/" + D.getYearMonth() + "_" + newFileName; 
 fileEntity.setLink(link); 
 
 boolean success = fileService.createEntity(fileEntity); 
 if (!success){ 
 throw new BusinessException(Status.FAIL_OPERATION, "上传文件失败"); 
 } 
 return fileEntity; 
} 
 
@Override 
public void updateFiles(List<String> uuids, Long currentId, boolean isCreate) { 
 // 如果不是创建,需要删除不在列表中的file记录 
 if (!isCreate){ 
 fileService.deleteEntities(Wrappers.<File>lambdaQuery().notIn(File::getUuid, uuids)); 
 } 
 // 进行相关更新 
 boolean success = fileService.updateEntity( 
  Wrappers.<File>lambdaUpdate() 
   .in(File::getUuid, uuids) 
   .set(File::getRelObjType, Demo.class.getSimpleName()) 
   .set(File::getRelObjId, currentId)); 
 if (!success){ 
 throw new BusinessException(Status.FAIL_OPERATION, "更新文件信息失败"); 
 } 
}

提示

该文章所有代码皆为方案示例,其中有些许删减,不确保能直接运行,如果各位有好的想法,欢迎一起探讨。

以上这篇antd form表单数据回显操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于JQuery的密码强度验证代码
Mar 01 Javascript
return false;和e.preventDefault();的区别
Jul 11 Javascript
基于mootools插件实现遮罩层新手引导
May 24 Javascript
JS实现鼠标单击与双击事件共存
Mar 08 Javascript
jQuery统计指定子元素数量的方法
Mar 17 Javascript
jQuery实现ctrl+enter(回车)提交表单
Oct 19 Javascript
javascript中错误使用var造成undefined
Mar 31 Javascript
微信小程序 检查接口状态实例详解
Jun 23 Javascript
jQuery实现拖动效果的实例代码
Jun 25 jQuery
JavaScript Drum Kit 指南(纯 JS 模拟敲鼓效果)
Jul 23 Javascript
jQuery 实时保存页面动态添加的数据的示例
Aug 14 jQuery
基于rollup的组件库打包体积优化小结
Jun 18 Javascript
antd Select下拉菜单动态添加option里的内容操作
Nov 02 #Javascript
Vue中使用Echarts仪表盘展示实时数据的实现
Nov 01 #Javascript
JavaScript实现刮刮乐效果
Nov 01 #Javascript
微信小程序实现单个或多个倒计时功能
Nov 01 #Javascript
微信小程序实现页面监听自定义组件的触发事件
Nov 01 #Javascript
uniapp微信小程序实现一个页面多个倒计时
Nov 01 #Javascript
uni-app使用countdown插件实现倒计时
Nov 01 #Javascript
You might like
PHP企业级应用之常见缓存技术篇
2011/01/27 PHP
设置php页面编码的两种方法示例介绍
2014/03/03 PHP
Linux下PHP加速器APC的安装与配置笔记
2014/10/24 PHP
Laravel 5框架学习之向视图传送数据(进阶篇)
2015/04/08 PHP
关于WordPress的SEO优化相关的一些PHP页面脚本技巧
2015/12/10 PHP
WordPress中用于检索模版的相关PHP函数使用解析
2015/12/15 PHP
PHP+HTML+JavaScript+Css实现简单爬虫开发
2016/03/28 PHP
php文件上传的两种实现方法
2016/04/04 PHP
smarty自定义函数用法示例
2016/05/20 PHP
PHP排序算法之冒泡排序(Bubble Sort)实现方法详解
2018/04/20 PHP
js 模拟实现类似c#下的hashtable的简单功能代码
2010/01/24 Javascript
jquery对dom的操作常用方法整理
2013/06/25 Javascript
JavaScript 事件入门知识
2015/04/13 Javascript
JS中处理时间之setUTCMinutes()方法的使用
2015/06/12 Javascript
使用snowfall.jquery.js实现爱心满屏飞的效果
2017/01/05 Javascript
JavaScript实现随机点名器实例详解
2019/05/07 Javascript
JS立即执行的匿名函数用法分析
2019/11/04 Javascript
vue 封装面包屑组件教程
2020/11/16 Javascript
python通过百度地图API获取某地址的经纬度详解
2018/01/28 Python
Tensorflow: 从checkpoint文件中读取tensor方式
2020/02/10 Python
python+selenium+chrome批量文件下载并自动创建文件夹实例
2020/04/27 Python
如何用css3实现switch组件开关的方法
2018/02/09 HTML / CSS
Timberland美国官网:全球领先的户外品牌
2016/08/15 全球购物
Expedia法国:全球最大在线旅游公司
2018/09/30 全球购物
allbeauty美国:英国在线美容店
2019/03/11 全球购物
Footshop法国:购买运动鞋
2020/01/19 全球购物
SQL Server 2000数据库的文件有哪些,分别进行描述。
2015/11/09 面试题
护士的岗位职责
2013/12/04 职场文书
诉讼代理人授权委托书
2014/04/08 职场文书
2014学习优秀共产党员先进事迹思想汇报
2014/09/14 职场文书
员工工作自我评价
2014/09/26 职场文书
督导岗位职责范本
2015/04/10 职场文书
2015年社区环境卫生工作总结
2015/04/21 职场文书
致我们终将逝去的青春观后感
2015/06/10 职场文书
《法国号》教学反思
2016/02/22 职场文书
2019年预备党员的思想汇报:加深对党的认知
2019/09/25 职场文书