Skip to content

Instantly share code, notes, and snippets.

@gahabeen
Last active September 17, 2020 04:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gahabeen/6ed9da45d4658c03b236753b5331fe54 to your computer and use it in GitHub Desktop.
Save gahabeen/6ed9da45d4658c03b236753b5331fe54 to your computer and use it in GitHub Desktop.
Extended FormulateSchema/FormulateForm Component as Plugin - for the amazing VueFormulate lib

This plugin extends the functionnalities of https://vueformulate.com/guide/forms/generating-forms/#schemas.

Extended FormulateSchema Component as Plugin

Added features are:

  • on property on a component with listeners

  • Add listeners in schema and listen them from the FormulateForm unded @events (as mentionned here)

  • Add nodeHook and componentHook to be able to interact with the generated components (like updating classes)

Note

  • Using Vue Composition API (Plugin for Vue 2 to use Vue 3 API), also you can easily tweak it for Vue 2
// ...
import Vue from 'vue'
import { plugin as ExtendedFormulateSchemaPlugin } from '@/plugins/formulate/FormulateSchemaPlugin'
import { plugin as ExtendedFormulateFormPlugin } from '@/plugins/formulate/FormulateForm'
Vue.use(VueFormulate, {
plugins: [ExtendedFormulateSchemaPlugin, ExtendedFormulateFormPlugin],
})
// ...
import FormulateForm from './FormulateForm.vue'
export function plugin(instance) {
instance.extend({
components: {
FormulateForm,
},
})
}
<template>
<form :class="classes" @submit.prevent="formSubmitted">
<FormulateSchema
v-if="schema"
:schema="schema"
:nodeHook="nodeHook"
:componentHook="componentHook"
@events="payload => $emit('events', payload)"
/>
<FormulateErrors v-if="!hasFormErrorObservers" :context="formContext" />
<slot />
</form>
</template>
<script>
import FormulateForm from "@braid/vue-formulate/src/FormulateForm";
import { FormulateSchema } from "./FormulateSchema";
export default {
...FormulateForm,
props: {
...FormulateForm.props,
nodeHook: FormulateSchema.props.nodeHook,
componentHook: FormulateSchema.props.componentHook
}
};
</script>
import Vue from 'vue'
import { createElement as h } from '@vue/composition-api'
import FormulateForm from '@braid/vue-formulate/src/FormulateForm'
const EventBus = new Vue()
export const FormulateSchema = {
functional: false,
props: {
schema: FormulateForm.props.schema,
nodeHook: {
type: Function,
default: (node) => node,
},
componentHook: {
type: Function,
default: (node) => h(node.component, node.definition, node.children),
},
},
setup(props, { emit }) {
EventBus.$on('events', (payload) => {
emit('events', payload)
})
/**
* Given an object and an index, complete an object for schema-generation.
* @param {object} item
* @param {int} index
*/
function leaf(item, index) {
if (item && typeof item === 'object' && !Array.isArray(item)) {
const { children = null, component = 'FormulateInput', depth = 1, events = [], on = {}, ...attrs } = item
const type = component === 'FormulateInput' ? attrs.type || 'text' : ''
const name = attrs.name || type || 'el'
const key = attrs.id || `${name}-${depth}-${index}`
const els = Array.isArray(children) ? children.map((child) => Object.assign(child, { depth: depth + 1 })) : children
const onExtended = {
...on,
...events.reduce((onEvents, event) => {
onEvents[event] = function (payload) {
if (on[event]) on[event](payload)
EventBus.$emit('events', { event, name, type, key, payload })
}
return onEvents
}, {}),
}
return props.nodeHook(Object.assign({ type, key, depth, component, definition: { attrs, on: onExtended }, children: tree(els) }))
}
return null
}
/**
* Recursive function to create vNodes from a schema.
* @param {Functon} h createElement
* @param {Array|string} schema
*/
function tree(schema) {
if (Array.isArray(schema)) {
return schema.map((el) => {
const item = leaf(el)
return props.componentHook(item)
})
}
return schema
}
return () => h('div', {}, tree(props.schema))
},
}
export function plugin(instance) {
instance.extend({
components: {
FormulateSchema,
},
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment