lljj-x / vue-json-schema-form

基于Vue/Vue3,Json Schema 和 ElementUi/antd/iview3/naiveUi 等生成 HTML Form 表单,用于活动编辑器、h5编辑器、cms等数据配置;支持可视化生成表单Schema 。 Generate a form using Vue/Vue3, Json Schema and ElementUi/antdv/iview3/naiveUi
https://form.lljj.me/
Apache License 2.0
2.01k stars 418 forks source link

Pass array via prop to custom Naive-ui slider component and use it for v-model #262

Closed BossHogg97 closed 1 year ago

BossHogg97 commented 1 year ago

Hi, i'm working with Naive and Vue3. I'm trying implement a custom slider (https://www.naiveui.com/en-US/os-theme/components/slider) with range option like the following image: image

I don't know how to pass to the slider component (custom widget) the model. Model of slider require an array of integer This is the code for ui:widget definition and props passing

const rangeValue = ref([50, 100])

schemaUI.value = {
    rollCenterDistanceMax: {
      'ui:title': 'rollCenterDistanceMax',
      'ui:widget': shallowRef(rangeSlider),
      'ui:minValue': 50,
      'ui:maxValue': 300,
      'ui:modelValue': rangeValue,
      'ui:options': {
        width: '100%',
      },
    },
}

Following the customComponent vue file:

<script setup lang="ts">
  type Props = {
    minValue: number
    maxValue: number

    modelValue: number[]
  }

  const emit = defineEmits(['update:modelValue'])
  const props = defineProps<Props>()

  const modelValue = computed({
    get() {
      return props.modelValue
    },
    set(value) {
      emit('update:modelValue', value)
    },
  })
</script>

<template>
  <div class="w-100">
    <n-space vertical>
      <n-slider v-model:value="modelValue" :min="props.minValue" :max="props.maxValue" range :step="1" />
    </n-space>
  </div>
</template>

Thanks for the patience :)

BossHogg97 commented 1 year ago

Edit: i changed the schema and now it looks like these:

....
"rollCenterDistanceMax": {
      "type": "array",
      "items": {
        "type": "number"
      }
    },
....

Then i change the component in this way:

<script setup lang="ts">
  type Props = {
    minValue: number
    maxValue: number

    rangeValue: number[]
  }

  const props = defineProps<Props>()

  const emit = defineEmits(['update:rangeValue'])
  const rangeValue = computed({
    get() {
      return props.rangeValue
    },
    set(value) {
      emit('update:rangeValue', value)
    },
  })
</script>

<template>
  <div class="w-100">
    <n-space vertical>
        <n-slider v-model:value="rangeValue" :min="props.minValue" :max="props.maxValue" range :step="1" />
    </n-space>
  </div>
</template>

This is the ui:widget definition inside schema:

rollCenterDistanceMax: {
      'ui:title': 'rollCenterDistanceMax',
      'ui:widget': shallowRef(rangeSlider),
      'ui:minValue': 50,
      'ui:maxValue': 300,
      'ui:rangeValue': rangeValue,
      'ui:options': {
        width: '100%',
      },
    },

And now i can see the range inside the slider but i cannot change the size of the slider. I think the problem is in rangeValue computed because it manage only one element of my array [rangeValue].

image

Any suggestion to manage the array in computed? Thanks!

BossHogg97 commented 1 year ago

I found the solution for the problem. Following the code for explanation:

This is the part of json schema:

"rollCenterDistanceMax": {
      "type": "array",
      "items": {
        "type": "integer"
      }
    },

Following the schemaUI definition:

schemaUI.value = {
    'ui:title': 'Stand RR custom filters',
    rollCenterDistanceMax: {
      'ui:title': 'rollCenterDistanceMax',
      'ui:widget': shallowRef(rangeSlider),
      'ui:minValue': minRollCenterDistanceMax,
      'ui:maxValue': maxRollCenterDistanceMax,
      'ui:modelValue': modelFilter,
      'ui:options': {
        width: '100%',
      },
    },
}

Finally the custom component:

<script setup lang="ts">
  import { NSlider } from 'naive-ui'

  type Props = {
    minValue: number
    maxValue: number

    modelValue: any
  }

  const props = defineProps<Props>()

  const emit = defineEmits(['update:modelValue'])
  const modelValue = computed({
    get() {
      return props.modelValue
    },
    set(value) {
      emit('update:modelValue', value)
    },
  })
</script>

<template>
  <div class="w-100">
    <n-slider v-model:value="modelValue" :min="props.minValue" :max="props.maxValue" range :step="1" />
  </div>
</template>
lljj-x commented 1 year ago

Yes, custom component v-model must usemodelValue as prop