QForm - Form Fields Generator



  • just working on a new component, essentially a form generator. You pass in the object that you want to ‘model’ and a schema for the object’s fields. Just a work in progress but looking for feedback and input. It currently only does q-input but eventually any of the quasar form components could be supported (the best way to do that is still unclear).

    seems like once this supports all the form compoenents it could be added to quasar. It’s really just a way to avoid hard coding a form template especially when a subform of a form might be dependent on a form field as in my use case where choosing a “type” requires a different set of input fields for that type…And too when one is using schemas (like json schemas) for their nosql database docments, like I am with feathersjs and nedb adding a few extra keys to handle the quasar form field type and its props is no big deal and avoids a lot of hard coding of html templates.

    <script>
    
    export default {
      data () {
        return {
        }
      },
      render (element) {
        return element('div', {}, this.makeForm(element))
      },
      props: ['values', 'schema'],
      methods: {
        makeForm (element) {
          let form = []
          console.log('values', this.values)
          for (let key in this.values) {
            let field =
            element('q-field', {
              props: {
                label: this.schema[key].label
              }
            }, [
              element(this.values[key].fieldType ? `q-${this.schema[key].fieldType}` : 'q-input', {
                props: {
    // put function here to get props given fieldType
                  value: this.values[key]
                },
                on: { input: (value) => {
                  this.values[key] = value
                  this.$emit('input', { name: key, value: value })
                }
                }
              })
            ]
            )// end field
            form.push(field)
            // console.log('field', key, field)
          }// end form field loop
          // console.log('the form object', form)
          return form
        }
      }
    }
    </script>
    
    <style lang="stylus">
    </style>
    

    Then in the calling component

          <q-collapsible class="col-11" v-on:remove v-on:add :label="device.name">
            <q-field label="Device Name">
             <q-input  v-model="device.name"/>
            </q-field>
            <q-field label="Type">
             <q-select v-model="device.type" :options="deviceTypesOptions()" />
            </q-field>
            <q-field label="Description">
              <q-input  v-model="device.desc"/>
            </q-field>
            <q-form class="" @input="update(device,$event)" :values="device.settings" :schema="deviceTypes[device.type].settings" ></q-form>
            <q-btn color="positive" @click="saveChanges(device,index)">Save Changes</q-btn>
          </q-collapsible>
    

    schema looks like this.

    // if no fieldType it's assumed to be q-input
     {
        i2cAddress : { type: Number, required: true, unique: true, fieldType: 'input', label: 'I2C Address', help: 'enter hex address' },
       defaultConfig: { type: String, required: true, default: 'output', fieldType: 'select', valids: ['toggle','momentary','input','output','custom'], label: 'pins mode', help: 'choose a mode for all pins on chip' },
        iPinA : { type: Number, label: 'SBC Pin Number' },
        iPinB : { type: Number, label: 'SBC Pin Number' }
     }


  • 0_1505527545904_Screenshot at 2017-09-15 19:03:55.png

    fields I2C Address and below come from the generator and changes to them emit to the parent form which then can update it’s data accordingly.



  • @dgk 😀 Nice! Make it an npm dependecy.



  • @leon I can do that when it’s more tested plus a a little tutorial/docs on use. I can put the work in progress on github sooner though.

    In the meantime I’ve added a q-collapse-form which wraps the form component, plus I have a quasar-feathers component so one can display all how set of configurable documents from a server.

    Below is the latest, multi-schema would look. With these schemas quasar renders a three tab page with each tab allowing editing of that document/schemas fields. Shema now uses a fieldprops key so one can set the props for any quasar form component. Option-group options can be hard coded or are created at run time from other feathers services. Works slick although I am having this tab display issue. http://forum.quasar-framework.org/topic/920/formatting-generated-q-tabs-also-getting-a-explict-keys-warning/2

    const virtual = {
    
      name: { default: '', unique: true,
        fieldProps: { label: 'Name', tip: 'enter unique circuit name' }
      },
      desc: { default: '',
        fieldProps: { label: 'Description', tip: 'Describe Services' }
      },
      circuits: { default: [], fieldType: 'option-group',
        fieldProps: { label: 'Circuits', tip: 'Select circuits associated with this switch', inline: true, type: 'toggle', options: [] }
      }
    };
    
    
    
    const physicalExtras = {
    
      mode: { default: 'toggle' , fieldType: 'select',
        fieldProps: { label: 'Switch Mode', tip: 'Select Switch Mode Type',
          options: [
            {label: 'Toggle', value: 'toggle'},
            {label: 'On/Off', value: 'onoff'},
            {label: 'Momentary', value: 'momentary'},
          ]}
      },
      virtual: { default: true , fieldType: 'checkbox',
        fieldProps: { label: 'Virtual Switch', tip: 'Create a corresponding virtual switch',
          }
      },
      // TODO make this another doc type so users can edit this list - for now disable
      location: { default: '1' , fieldType: 'hidden',
        fieldProps: { label: 'Location in Buidling', tip: 'Select building location',
          options: [
            {label: 'First Floor', value: '1'},
            {label: 'Second Floor', value: '2'},
            {label: 'Outside', value: 'outside'}
    
          ]}
      },
      bankid: { default: '', fieldType: 'select',
        fieldProps: { label: 'Bank/Board', tip: 'Select Bank/Board', options: [] }
      },
      port: { default: 'A', fieldType: 'select',
        fieldProps: { label: 'Port', tip: 'Select a Port',
          options: [
            {label: 'Port A', value: 'A'},
            {label: 'Port B', value: 'B'}
          ]}
      },
      pin: { default: 1,
        fieldProps: { label: 'Relay/Pin Number',min: 1, max: 8, step: 1 }
        //tip: 'Select a relay/pin number with the port '
      }
    
    };
    
    const physical = Object.assign({}, virtual);
    Object.assign(physical, physicalExtras);
    
    // views only for virtual switches
    virtual.views = { default: [],  fieldType: 'option-group',
        fieldProps: { label: 'Views', tip: 'Put this switch in checked views', type: 'toggle', options: [] }
      }
    
    const view = {
    
      name: { default: '', unique: true,
        fieldProps: { label: 'view name', tip: 'enter unique view name' }
      }
    
    };
    
    
    module.exports = { physical, virtual, view };
    


  • I need something like this for my new project.

    Could you use JSON schema spec for this?

    Found a bunch of dead projects like this but not for Quasar components.

    Basically looking for this https://github.com/icebob/vue-form-generator/



  • yes this is pretty close to JSON schema spec since it’s just json disguised as javascript. I like to write my json this way so I can use comments and easier to lint and I can also combine partical schemas programatically.

    See this https://github.com/uCOMmandIt/backend/tree/master/src/schemas

    This is all part of a working lightning system I just installed. No time now to share in a constructive way but check out the repo for now. You’ll see I set this up as a dual component. On for a form and one that uses a form in a collapsible. The schema is fetched from the backend as it’s used to build forms and also initialize a nosql document

    https://github.com/uCOMmandIt/frontend

    all check out my post here.
    http://forum.quasar-framework.org/topic/933/getting-proxied-server-data-to-play-app/4



  • Any progress? I would love to use/contribute to this type of component.
    One of the options is to form the vue-form-generator and migrate the input types to quasar components.



  • vue-form-json-schema supports any library. I’m testing it with Quasar now. It allows you to layout the UI as well so you don’t have a single ugly column for your forms too. Just all around butt-kicking. 🙂

    If you’re already using ajv for your schemas (if not you SHOULD) and lodash (who doesn’t), you’ll be happy to know this entire form generator weighs in at under 20kb gzipped, smaller than all other form generators, and with TONS more features! (see https://bundlephobia.com/result?p=vue-form-json-schema@2.5.3)

    github: https://github.com/jarvelov/vue-form-json-schema
    detailed docs with demos: https://jarvelov.gitbook.io/vue-form-json-schema/



  • WOW. Just… WOW. I spent a day testing vue-form-json-schema, and not only is it FULLY Quasar compatible, you can literally use this to create ENTIRE LAYOUTS not just a single Quasar form… HOLY COW is it powerful with Quasar… 🤯

    For anyone that would like to quickly use vue-form-json-schema with Quasar, here is some of my testing work… ☺

    Just “npm i vue-form-json-schema” in your Quasar project, create a component and paste this code into it…

    <template>
    <div class="">
       <vue-form-json-schema
        v-model="value"
        :schema="schema"
        :ui-schema="uiSchema"
        v-on:state-change="onChangeState"
        v-on:validated="onValidated"
        :components="components"
      />
    </div>
    
    </template>
    
    <script>
    import { QInput, QCard, QExpansionItem } from 'quasar'
    import VueFormJsonSchema from 'vue-form-json-schema/dist/vue-form-json-schema.esm.js'
    export default {
      props: ['value', 'schema', 'uiSchema'],
      components: {
        VueFormJsonSchema
      },
      data () {
        return {
          components: { // Add your sandboxed quasar or other components here (if you don't add it here, you can't use them)
            'input': QInput,
            'card': QCard,
            'expansion': QExpansionItem
          }
        }
      },
      methods: {
        onChange (value) {
          this.$emit('change', value)
        },
        onChangeState (value) {
          this.$emit('state', value)
        },
        onValidated (value) {
          this.$emit('valid', value)
        }
      }
    }
    </script>
    

    Then from anywhere in app, add this to your template (you’ll have to add the above component to your project as well of course):

    <form-generator v-model="yourModel" :schema="yourSchema" :uiSchema="yourUISchema"/>
    

    If you want some quick data that you can use to just see it working immediately, here is a q-card, with padding and spacing set, and inside it 2 input items, and they are all generated right from schema that you can put into config 🤯

    yourModel: {
            firstName: '', lastName: ''
          },
          yourSchema: {
            type: 'object',
            properties: {
              firstName: {
                type: 'string'
              },
              lastName: {
                type: 'string'
              }
            }
          },
          yourUISchema: [
            {
              component: 'card',
              fieldOptions: {
                class: ['q-ma-xl', 'q-pa-md']
              },
              children: [
                {
                  component: 'input',
                  model: 'firstName',
                  fieldOptions: {
                    on: ['input'],
                    props: { outlined: true, label: 'First Name' }
                  }
                },
                {
                  component: 'input',
                  model: 'lastName',
                  fieldOptions: {
                    props: { rounded: true, outlined: true, label: 'Last Name' },
                    class: ['q-pa-xl'],
                    on: ['input']
                  }
                }
              ]
            }
          ]
    


  • @njsteele Thank you for your example! It really is awesome with quasar.
    Do you know by any chance how/if the import of the quasar components can be skipped and ‘input’ be directly replaced with ‘q-input’?

              ...
              children: [
                {
                  #component: 'input',
                  component: 'q-input',
                  model: 'firstName',
                  fieldOptions: {
              ...
    

    Something simillar is done in the fourth example in the documentation but I cant get it to work with quasar in the same way.


Log in to reply