koumoul-dev / vuetify-jsonschema-form

Create beautiful and low-effort forms that output valid data. Published on npm as @koumoul/vjsf.
https://koumoul-dev.github.io/vuetify-jsonschema-form/latest/
MIT License
538 stars 154 forks source link

x-step/step doesn't work with vuetify #165

Open StephanieeV opened 3 years ago

StephanieeV commented 3 years ago

Hello

I have several input of 'number' type. I want to have a step at 0.01 for example. I try to add step props or x-step, it doesn't work. I see, in the code, that i don't need to add step or x-step if i have an input of 'number' type but the actual step is 1 when i typing in my input. I also try to "console.log" the step that give 0.01.

I think there is a problem in vuetify or vuetify-jsonschema-form. I use the latest version of vuetify and vuetify-jsonschema-form.

Can you help me or give me explanations? please

Thank you a lot.

albanm commented 3 years ago

You are right, this does not work. I think it used to work in vuetify v1, when I first wrote this lib.

But I don't see how to repair that in vjsf as I don't see how it can be done with vuetify itself. Do you have a solution in pure vuetify ?

Cirrusware commented 3 years ago

Hello Alban,

You must add const attrs = {} to renderSimpleProp attrs.step = this.fullSchema['x-step'] || (this.fullSchema.type === 'integer' ? 1 : 0.01) and return tag ? [h(tag, { props, domProps, attrs, on, scopedSlots }, children)] : null

Attention to another attributes (maxlength and others)

Thanks

renderSimpleProp(h) {
      if (!this.isSimpleProp) return
      let tag
      const props = { ...this.commonFieldProps }
      const attrs = {}

      const domProps = {}
      const children = [...this.renderPropSlots(h)]
      const on = {
        input: value => this.input(value),
        change: value => this.change(value)
      }
      const scopedSlots = {}
      let tooltipSlot = 'append-outer'

      if (this.fullSchema.type === 'string') {
        if (this.display === 'textarea' || (this.fullSchema.maxLength && this.fullSchema.maxLength > 1000 && this.display !== 'single-line')) {
          tag = 'v-textarea'
          Object.assign(props, this.fullOptions.textareaProps)
          domProps.class = 'v-text-field--box v-text-field--enclosed'
        } else {
          tag = 'v-text-field'
          Object.assign(props, this.fullOptions.textFieldProps)
          if (this.display === 'password') props.type = 'password'
        }
      }

      if (['number', 'integer'].includes(this.fullSchema.type)) {
        if (this.display === 'slider') {
          tag = 'v-slider'
          Object.assign(props, this.fullOptions.sliderProps)
        } else {
          tag = 'v-text-field'
          Object.assign(props, this.fullOptions.textFieldProps)
          Object.assign(props, this.fullOptions.numberProps)
        }
        props.type = 'number'
        if (this.fullSchema.minimum !== undefined) props.min = this.fullSchema.minimum
        if (this.fullSchema.maximum !== undefined) props.max = this.fullSchema.maximum
        attrs.step = this.fullSchema['x-step'] || (this.fullSchema.type === 'integer' ? 1 : 0.01)

        on.input = value => this.input(this.fullSchema.type === 'integer' ? parseInt(value, 10) : parseFloat(value))
      }

      if (this.fullSchema.type === 'boolean') {
        tooltipSlot = 'append'
        if (this.display === 'switch') {
          tag = 'v-switch'
          Object.assign(props, this.fullOptions.switchProps)
        } else {
          tag = 'v-checkbox'
          Object.assign(props, this.fullOptions.checkboxProps)
        }
        on.change = value => {
          this.input(value || false)
          this.change(value || false)
        }
      }

      if (this.fullSchema.type === 'array' && ['string', 'number', 'integer'].includes(this.fullSchema.items.type)) {
        tag = 'v-combobox'
        Object.assign(props, this.fullOptions.comboboxProps)
        props.chips = true
        props.multiple = true
        props.appendIcon = ''
        props.type = 'string'
        props.validateOnBlur = true
        const itemRules = getRules(schemaUtils.prepareFullSchema(this.fullSchema.items), this.fullOptions)
        props.rules = props.rules.concat([(values) => {
          const valuesMessages = values.map(value => {
            const brokenRule = itemRules.find(rule => {
              return typeof rule(value) === 'string'
            })
            return brokenRule && brokenRule(value)
          })
          const firstMessage = valuesMessages.find(m => !!m)
          return firstMessage || true
        }])

        if (this.fullSchema.items.type !== 'string') {
          props.type = 'number'
          on.input = value => {
            const vals = value
              .map(val => this.fullSchema.items.type === 'integer' ? parseInt(val, 10) : parseFloat(val))
              .filter(val => !isNaN(val))
            this.input(vals)
          }
        }

        scopedSlots.selection = slotProps => {
          const onClose = () => {
            this.value.splice(slotProps.index, 1)
            this.input(this.value)
            this.change(this.value)
          }
          const brokenRule = itemRules.find(rule => {
            return typeof rule(slotProps.item) === 'string'
          })
          return h('v-chip', {
            props: { close: true, color: brokenRule ? 'error' : 'default' },
            on: { 'click:close': onClose }
          }, slotProps.item)
        }
      }

      if (this.htmlDescription) {
        children.push(this.renderTooltip(h, tooltipSlot))
      }

      tag = this.customTag ? this.customTag : tag

      return tag ? [h(tag, { props, domProps, attrs, on, scopedSlots }, children)] : null
    }
afmorielo commented 1 year ago

Facing the same issue here! What I tried:

{ "type":"number", "title":"Longitude (deg)", "description":"", "x-step":"0.1", "minimum":-180, "maximum":180 },

But the step is still rounded to 1, tested in both Chrome and Firefox.

vuetify@2.6.14 @koumoul/vjsf@2.21.3