Create a custom button with useModel #61
-
I want to create a onetime button that could store it's state. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 4 replies
-
Option 1 - Create a new elementYou can create a new Vueform element first based on this guide: New elements always have a model by default. You can add a template and features based on the Then you could add it as a Builder element: Option 2 - Create a plugin and custom template for
|
Beta Was this translation helpful? Give feedback.
-
Thanks @adamberecz for response! I've created a new element based on ButtonElement, but I have some problems:
My custom Button: <template>
<ElementLayout>
<template #element>
<button-element v-if="!isDisabled && !isReadonly"
v-bind="$props"
@click="onClickHandler"
>
{{ buttonLabel || 'Save' }}
</button-element>
</template>
</ElementLayout>
</template>
<script>
import useForm$ from '@vueform/vueform/src/composables/useForm$'
import useTheme from '@vueform/vueform/src/composables/useTheme'
import useConditions from '@vueform/vueform/src/composables/useConditions'
import useLabel from '@vueform/vueform/src/composables/elements/useLabel'
import useColumns from '@vueform/vueform/src/composables/elements/useColumns'
import useView from '@vueform/vueform/src/composables/elements/useView'
import useTemplates from '@vueform/vueform/src/composables/elements/useTemplates'
import useSlots from '@vueform/vueform/src/composables/elements/useSlots'
import useButton from '@vueform/vueform/src/composables/elements/useButton'
import useLayout from '@vueform/vueform/src/composables/elements/useLayout'
import useEvents from '@vueform/vueform/src/composables/useEvents'
import useClasses from '@vueform/vueform/src/composables/elements/useClasses'
import useFieldId from '@vueform/vueform/src/composables/elements/useFieldId'
import useFocus from '@vueform/vueform/src/composables/elements/useFocus'
import useValue from '@vueform/vueform/src/composables/elements/useValue';
import useData from '@vueform/vueform/src/composables/elements/useData';
import useDefault from '@vueform/vueform/src/composables/elements/useDefault'
import useValidation from '@vueform/vueform/src/composables/elements/useValidation'
import useNullValue from "@vueform/vueform/src/composables/elements/useNullValue.js";
import {button as useDisabled} from '@vueform/vueform/src/composables/elements/useDisabled'
import {button as useA11y} from '@vueform/vueform/src/composables/elements/useA11y'
import {static_ as useBaseElement} from '@vueform/vueform/src/composables/elements/useBaseElement'
import {static_ as usePath} from '@vueform/vueform/src/composables/elements/usePath'
import {static_ as useElement} from '@vueform/vueform/src/composables/useElement'
import BaseElement from '@vueform/vueform/src/mixins/BaseElement'
import HasView from '@vueform/vueform/src/mixins/HasView'
import HasChange from '@vueform/vueform/src/mixins/HasChange'
import HasData from '@vueform/vueform/src/mixins/HasData'
import HasValidation from '@vueform/vueform/src/mixins/HasValidation'
import {defineElement} from "@vueform/vueform";
// todo: delete element cause isStatic reading error
// todo: button in a single container doesn't set form value
export default defineElement({
...ButtonElement,
name: 'SaveContainerButtonElement',
mixins: [BaseElement, HasView, HasChange, HasData, HasValidation],
emits: ['change', 'beforeCreate', 'created', 'beforeMount', 'mounted', 'beforeUpdate', 'updated', 'beforeUnmount', 'unmounted'],
props: {
default: {
required: false,
type: Boolean,
default: false
},
},
setup(props, context) {
context.features = [
useForm$,
useTheme,
useLayout,
usePath,
useEvents,
useBaseElement,
useDisabled,
useDefault,
useConditions,
useValidation,
useValue,
useData,
useConditions,
useLabel,
useView,
useTemplates,
useFieldId,
useButton,
useClasses,
useColumns,
useSlots,
useA11y,
useFocus,
]
context.slots = [
'label', 'info', 'description',
'before', 'between', 'after', 'default',
]
return {
...useElement(props, context)
}
},
methods: {
onClickHandler() {
this.update(true);
this.$emit('click');
console.log('SaveContainerButtonElement onClick', this.value);
}
},
});
</script> initialization in builder: saveContainerButton: {
label: 'Save container button',
description: 'Save container data and lock it',
icon: '/assets/images/floppy-disk-icon.svg',
category: 'fields',
schema: {
type: 'save-container-button',
name: 'save-button',
buttonLabel: 'Save',
buttonType: 'button',
defaultValue: false,
submit: true,
resets: false,
},
sections: {
properties: {
name: 'properties',
label: 'Properties',
fields: {
type: {type: TypeField},
name: {type: NameField},
label: {type: LabelField},
tooltip: {type: InfoField},
description: {type: DescriptionField},
},
},
options: {
name: 'options',
label: 'Options',
fields: {
buttonLabel: {type: ButtonLabelField},
buttonType: {type: ButtonTypeField},
},
},
data: {
name: 'data',
label: 'Data',
fields: {
submit: {type: SubmitField},
},
},
decorators: false,
layout: {
name: 'layout',
label: 'Layout',
fields: {
full: {type: FullField},
align: {type: AlignField},
size: {type: SizeField},
columns: {type: ColumnsField},
},
},
conditions: {
name: 'conditions',
label: 'Conditions',
fields: {
conditions: {type: ConditionsField},
},
},
attributes: {
name: 'attributes',
label: 'Attributes',
fields: {
disabled: {type: DisabledField},
id: {type: IdField},
},
},
},
separators: {
properties: [
['type', 'name'],
['label', 'tooltip'],
['description'],
],
}
},] |
Beta Was this translation helpful? Give feedback.
-
It might help someone or for docs. <script>
import ButtonElement from '@vueform/vueform/src/components/elements/ButtonElement'
import ButtonTemplate from '@vueform/vueform/themes/blank/templates/elements/ButtonElement.vue'
import {classes} from '@vueform/vueform/dist/tailwind'
import useForm$ from '@vueform/vueform/src/composables/useForm$'
import useTheme from '@vueform/vueform/src/composables/useTheme'
import useConditions from '@vueform/vueform/src/composables/useConditions'
import useLabel from '@vueform/vueform/src/composables/elements/useLabel'
import useColumns from '@vueform/vueform/src/composables/elements/useColumns'
import useView from '@vueform/vueform/src/composables/elements/useView'
import useTemplates from '@vueform/vueform/src/composables/elements/useTemplates'
import useSlots from '@vueform/vueform/src/composables/elements/useSlots'
import useButton from '@vueform/vueform/src/composables/elements/useButton'
import useLayout from '@vueform/vueform/src/composables/elements/useLayout'
import useEvents from '@vueform/vueform/src/composables/useEvents'
import useClasses from '@vueform/vueform/src/composables/elements/useClasses'
import useFieldId from '@vueform/vueform/src/composables/elements/useFieldId'
import useFocus from '@vueform/vueform/src/composables/elements/useFocus'
import useValue from '@vueform/vueform/src/composables/elements/useValue';
import useData from '@vueform/vueform/src/composables/elements/useData';
import useDefault from '@vueform/vueform/src/composables/elements/useDefault'
import useValidation from '@vueform/vueform/src/composables/elements/useValidation'
import useElement from '@vueform/vueform/src/composables/useElement'
import useBaseElement from '@vueform/vueform/src/composables/elements/useBaseElement'
import usePath from '@vueform/vueform/src/composables/elements/usePath'
import useDisabled from '@vueform/vueform/src/composables/elements/useDisabled'
import useLoading from '@vueform/vueform/src/composables/elements/useLoading'
import useNullValue from '@vueform/vueform/src/composables/elements/useNullValue'
import {button as useA11y} from '@vueform/vueform/src/composables/elements/useA11y'
export default {
name: 'ConciseCustomButtonElement',
render: ButtonTemplate.render, // Original template is used to render the button
// extends: ButtonElement, // It's useless for ButtonElement
mixins: [
...ButtonElement.mixins,
// HasChange, HasData, HasValidation // additional mixins
],
emits: [
...ButtonElement.emits,
// 'change' // additional events
],
props: {
...ButtonElement.props,
// additional props
// default: {
// type: Object,
// default: null
// },
},
setup(props, ctx) {
const context = {...ctx}
// IMPORTANT: need to completely copy and extend ButtonElement context
// Order matters! Features should be arranged based on their dependencies
context.features = [
// Core features first
useForm$,
useTheme,
// Path and base features
usePath,
useEvents,
useBaseElement,
// Element state features
// useNullValue, // Must come before useDefault and useValue
// useDefault, // Must come before useValue
// useValue, // Depends on useNullValue and useDefault
// Validation and conditions
useConditions, // Depends on useValue
// useValidation, // required for non-static elements
// Data and change tracking
// useData, // Depends on useValue, useValidation
// UI and interaction features
useDisabled,
useLayout,
useLabel,
useView,
useTemplates,
useFieldId,
useButton,
useClasses,
useColumns,
useSlots,
useA11y,
useFocus,
]
context.slots = [
'label', 'info', 'description',
'before', 'between', 'after', 'default',
]
return {
...useElement(props, context),
defaultClasses: {
// TODO: I haven't find the way to get config related styles from the theme
...classes.ButtonElement,
},
};
},
}
</script> |
Beta Was this translation helpful? Give feedback.
Try to take a slightly different approach. Let's get rid of
defineElement
altogether which wouldn't be necessary anyway as we're defining an element with composables from ground up. Let's also use non-static exports of the composables (as our element is no longer considered static because it has data) and adduseNullValue
.Here's what you should get: