xaboy / form-create

:fire::fire::fire: 强大的低代码动态表单组件,通过数据驱动表单渲染,适配移动端,支持可视化设计。提高开发者对表单的开发效率。目前在政务系统、OA系统、ERP系统、电商系统、流程管理等系统中已稳定应用。
https://www.form-create.com/
MIT License
5.97k stars 960 forks source link

数组组件如何修改字段 #690

Closed hanfengcan closed 2 months ago

hanfengcan commented 5 months ago

@form-create/naive-ui: ^3.1.28

数组组件如何对字段进行setValue

{
  type: 'group',
  props: {
    rule: [
      ...字段1,
      ...字段2,
      {
        type: 'select',
        update(value, rule, fApi) {
          fApi.setValue(‘字段1’, 1)
          fApi.setValue(‘字段1’, 2)
        }
      }
    ]
}

在数组表单里面进行update监听,修改字段后,在最外层进行formData()读取不到设置的内容。对于数组表单,应该如何操作

xaboy commented 4 months ago

这边没有复现, 测试setValue后,group组件和最外层表单的值会同步变化

hanfengcan commented 4 months ago

哦,那我在测试测试

hanfengcan commented 3 months ago
<template>
  <form-create
    class="fc"
    :rule="itemConf.rule"
    :option="itemConf.option"
    @update:api="itemConf.fApi = $event"
  ></form-create>
  <div>
    <n-button class="ml-4" @click="add">add</n-button>
    <n-button type="primary" class="ml-4" @click="get">get</n-button>
  </div>
</template>

<script setup>
import { nextTick, onBeforeUnmount, onMounted, ref, toRaw, watch } from 'vue'

/**@type {import('@form-create/naive-ui').FormRule[]} */
const rule = [
  {
    type: 'group',
    field: 'msgConf',
    props: {
      defaultValue: { type: 'msg' },
      /**@type {import('@form-create/naive-ui').FormRule[]} */
      rule: [
        {
          type: 'select',
          title: '类型',
          field: 'type',
          options: [
            { label: '消息', value: 'msg' },
            { label: '弹窗', value: 'mod' },
          ],
        },
        {
          type: 'input',
          title: '触发条件',
          field: 'condition',
          props: {
            type: 'textarea',
            placeholder: '请输入jsonata表达式',
          },
          // suffix: {
          //   type: 'span',
          //   children: [{ type: 'i', class: 'add i-me:terminal-box-line ml-4' }],
          // },
        },
        {
          type: 'input',
          title: '提示内容',
          field: 'msgVal',
          suffix: {
            type: 'span',
            children: [{ type: 'i', class: 'add i-fe:eye ml-4' }],
          },
        },
      ],
    },
  },
]
const itemConf = {
  rule,
  /**@type {import("@form-create/naive-ui").Api} */
  fApi: {},
  /**@type {import("@form-create/naive-ui").Options} */
  option: {
    submitBtn: false,
    form: {
      labelWidth: 70,
    },
    row: {
      'item-responsive': true,
      'x-gap': 10,
    },
    col: {
      span: '24',
    },
    wrap: {
      // style: 'user-select: none;',
    },
  },
}

function get() {
  console.log(itemConf.fApi.formData())
}
function add() {
  itemConf.fApi.setValue({
    msgConf: [{ type: 'msg' }, { type: 'msg' }],
  })
}

onMounted(() => {
  console.log('hello')
})
</script>

以上这个demo,通过coverValue或者setValue,设置值后,界面没有变化。但是设置值后获取值就有内容。

image

hanfengcan commented 3 months ago

官网的例子也不行

<template>
  <div>
    <p>value: {{ value.group }}</p>
    <form-create v-model:api="fApi" v-model="value" :rule="rule" :option="options" />
  </div>
</template>

<script setup>
import { onMounted } from 'vue'
let fApi = {}
let value = {}
let options = {
  onSubmit: (formData) => {
    alert(JSON.stringify(formData))
  },
}
let rule = [
  {
    type: 'group',
    field: 'group',
    title: 'group',
    value: [],
    props: {
      defaultValue: { field1: 'field1', field2: 'field2' },
      rule: [
        { type: 'input', field: 'field1', title: 'field1' },
        { type: 'input', field: 'field2', title: 'field2' },
      ],
    },
  },
]
onMounted(() => {
  fApi.coverValue({
    group: [{ field1: '122', field2: '222' }],
  })
})
</script>

image

hanfengcan commented 3 months ago

官网的例子也不行

<template>
  <div>
    <p>value: {{ value.group }}</p>
    <form-create v-model:api="fApi" v-model="value" :rule="rule" :option="options" />
  </div>
</template>

<script setup>
import { onMounted } from 'vue'
let fApi = {}
let value = {}
let options = {
  onSubmit: (formData) => {
    alert(JSON.stringify(formData))
  },
}
let rule = [
  {
    type: 'group',
    field: 'group',
    title: 'group',
    value: [],
    props: {
      defaultValue: { field1: 'field1', field2: 'field2' },
      rule: [
        { type: 'input', field: 'field1', title: 'field1' },
        { type: 'input', field: 'field2', title: 'field2' },
      ],
    },
  },
]
onMounted(() => {
  fApi.coverValue({
    group: [{ field1: '122', field2: '222' }],
  })
})
</script>

image

把UI切换成饿了么,发现去除value:[]这行就可以正常显示。断点跟踪到,setValue成功后,触发了watch。重新设置成[]

xaboy commented 3 months ago

感谢反馈, 我这边检查一下 @hanfengcan

hanfengcan commented 3 months ago

感谢反馈, 我这边检查一下 @hanfengcan

感谢回复。我测试了。如果是naive-ui。这样写,就能正常显示

onMounted(async () => {
  console.log(fApi.value.setValue)
  await nextTick()
  fApi.value.setValue({
      group: [{field1: 'aaa', field2: 'sss'}, {field1: 'aaa', field2: 'sss'}]
    })
})

这个组件太庞大了,不知道如何定位问题,附上测试代码 demo.zip

hanfengcan commented 3 months ago
<template>
  <form-create
    class="fc"
    :rule="itemConf.rule"
    :option="itemConf.option"
    @update:api="itemConf.fApi = $event"
  ></form-create>
  <div>
    <n-button class="ml-4" @click="add">add</n-button>
    <n-button type="primary" class="ml-4" @click="get">get</n-button>
  </div>
</template>

<script setup>
import { nextTick, onBeforeUnmount, onMounted, ref, toRaw, watch } from 'vue'

/**@type {import('@form-create/naive-ui').FormRule[]} */
const rule = [
  {
    type: 'group',
    field: 'msgConf',
    props: {
      defaultValue: { type: 'msg' },
      /**@type {import('@form-create/naive-ui').FormRule[]} */
      rule: [
        {
          type: 'select',
          title: '类型',
          field: 'type',
          options: [
            { label: '消息', value: 'msg' },
            { label: '弹窗', value: 'mod' },
          ],
        },
        {
          type: 'input',
          title: '触发条件',
          field: 'condition',
          props: {
            type: 'textarea',
            placeholder: '请输入jsonata表达式',
          },
          // suffix: {
          //   type: 'span',
          //   children: [{ type: 'i', class: 'add i-me:terminal-box-line ml-4' }],
          // },
        },
        {
          type: 'input',
          title: '提示内容',
          field: 'msgVal',
          suffix: {
            type: 'span',
            children: [{ type: 'i', class: 'add i-fe:eye ml-4' }],
          },
        },
      ],
    },
  },
]
const itemConf = {
  rule,
  /**@type {import("@form-create/naive-ui").Api} */
  fApi: {},
  /**@type {import("@form-create/naive-ui").Options} */
  option: {
    submitBtn: false,
    form: {
      labelWidth: 70,
    },
    row: {
      'item-responsive': true,
      'x-gap': 10,
    },
    col: {
      span: '24',
    },
    wrap: {
      // style: 'user-select: none;',
    },
  },
}

function get() {
  console.log(itemConf.fApi.formData())
}
function add() {
  itemConf.fApi.setValue({
    msgConf: [{ type: 'msg' }, { type: 'msg' }],
  })
}

onMounted(() => {
  console.log('hello')
})
</script>

以上这个demo,通过coverValue或者setValue,设置值后,界面没有变化。但是设置值后获取值就有内容。

image

这里的itemConf需要用reactive包起来

xaboy commented 2 months ago

需要把itemConf和rule转换成响应式的, 分别用reactive和ref包起来. 我这边测试功能正常的 @hanfengcan