-
-
Notifications
You must be signed in to change notification settings - Fork 129
Extend a new Control
For a good reason, sometimes we must extend a new control for our special cases. This has to be done in order to reach the requirement from the end-users, customers,...
So "Extensible" is very important. That's why I found a solution to deal with.
- Vue knowledge
- JS knowledge
To extend a new control, we need to prepare 3 Vue Components:
- Template component - How the control will look like in the Configuration/Template page
- Sidebar component - To handle your own data/config for your custom control
- GUI Component - To show up for the end-users.
After that, we will provide it so Vue-Form-Builder can inject your components into its lifecycle.
Note: You don't need to fork my project and build your own library to deal with this. You can create the Vue Component in your current project. Let me show you more below.
For example, I will create a new control using this library http://www.bootstraptoggle.com/ instead of using a normal checkbox.
Options is an object that you need to pass into the FormBuilder component. Basically:
// template
<form-builder type="template" :options="myOption"></form-builder>
// your data:
{
data: {
myOption: {}, // object
}
}
For the options
, you need a property named moreControls
inside. It's an object too and the structure should look like this: https://github.com/sethsandaru/vue-form-builder/blob/master/src/config/control_constant.js
In the end for the toggle
, I supposed to have 3 components already. So let me define the custom-control for Vue-FormBuilder:
<form-builder type="template" :options="myOption"></form-builder>
// data:
<script>
[...]
// import stuff here
import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck'; // re-use like checkbox :(
// Import Components - REMEMBER TO CHANGE YOUR PATH TO YOUR COMPONENTS :D
import GUI_ToggleControl from '@mypath/gui/ToggleControl';
import TEMPLATE_ToggleControl from '@mypath/template/ToggleControl';
import SIDEBAR_ToggleControl from '@mypath/sidebar_items/ToggleConfigControl';
export default {
data() {
return {
myOption: {
moreControls: {
toggle: {
label: "Bootstrap Toggle",
icon: faCheck, // please change to another icon if you want, remember import.
source: {
gui: GUI_ToggleControl, // register component here
template: TEMPLATE_ToggleControl,
config: SIDEBAR_ToggleControl,
}
},
[... more custom controls??]
}
}
}
}
}
</script>
** This must be the last step that you do. Therefore the Form should be running **
** Please remember not to use the duplicated key from constant [CONSTANT_FILE](https://github.com/sethsandaru/vue-form-builder/blob/master/src/config/control_constant.js). Otherwise your control will not be injected**
Because of the toggle is based on the checkbox concept. So I will copy the Checkbox Template Control which already created in the Vue Form Builder.
Normal code: https://github.com/sethsandaru/vue-form-builder/blob/master/src/template/ui/common/controls/CheckboxControl.vue
You can see that we have 2 props and we can use the control
object and labelPosition
string.
For the "labelPosition" concept, please check it out at the Documentation for the Vue Form Template. Typically, we got 2 position is top and left. So that's why you will see my v-if v-if="labelPosition === 'left'"
For the control object. Here is the sample data, it's just an object to contains the configuration of the control.
{
"type": "text",
"name": "control_text_336499",
"fieldName": "DocumentID",
"label": "Document Number",
"order": 0,
"defaultValue": "",
"value": "",
"className": "col-md-5",
"readonly": false,
"labelBold": false,
"labelItalic": false,
"labelUnderline": false,
"required": true,
"isMultiLine": false,
"isInteger": false,
"decimalPlace": 0,
"isTodayValue": false,
"dateFormat": "dd/mm/yy",
"isNowTimeValue": false,
"timeFormat": "HH:mm",
"isMultiple": false,
"isAjax": false,
"dataOptions": [],
"ajaxDataUrl": "",
"isChecked": false
}
Because of the Toggle basically a CheckBox => I'll re-use the isChecked
property.
So I'm creating a new Vue Component: "TemplateToggleControl.vue" in my own project.
<template>
<div class="controlItemWrapper" :class="control.className" :data-control-name="control.name">
<div class="controlItem row" :id="control.name" v-if="labelPosition === 'left'">
<div class="col-md-4">
<label :class="{'bold': control.labelBold, 'italic': control.labelItalic, 'underline': control.labelUnderline}">
{{control.label}}
</label>
</div>
<div class="col-md-8 input-group">
<div class="text-center w-100 toggle-container">
<input type="checkbox" :name="control.fieldName" :checked="control.isChecked">
</div>
</div>
</div>
<div class="controlItem row" :id="control.name" v-else>
<div class="form-group col-md-12">
<label :class="{'bold': control.labelBold, 'italic': control.labelItalic, 'underline': control.labelUnderline}">
{{control.label}}
</label>
<div class="input-group">
<div class="text-center w-100 toggle-container">
<input type="checkbox" :name="control.fieldName" :checked="control.isChecked">
</div>
</div>
</div>
</div>
</div>
</template>
Basically we just init the control in mounted
hook and destroy control in beforeDestroy
hook
<script>
// REMEMBER: To import your special stuff here :D
require('path/to/my/stuff/bootstrap-toggle.min.js');
require('path/to/my/stuff/bootstrap-toggle.min.css');
export default {
name: "ToggleControl", // Change Name
props: ['control', 'labelPosition'], // core-basic data, don't change that if you don't know anything about it.
mounted() {
$(this.$el).find(".toggle-container > input") // look for the input-checkbox
.bootstrapToggle(); // run the init
},
beforeDestroy() {
// have to destroy the control to reduce ram, dom,... https://vuejs.org/v2/cookbook/avoiding-memory-leaks.html
$(this.$el).find(".toggle-container > input")
.bootstrapToggle('destroy'); // destroy it
}
}
</script>
Normal code: https://github.com/sethsandaru/vue-form-builder/blob/master/src/template/ui/sidebar_items/CheckboxConfigComponent.vue
Basically I don't need to change much. But if your control have some specific things to config. Please define it here including the template itself.
The control
object is the same like above.
Also, please don't change directly the data to control in the hook (created, mounted) or methods. Vue will show an error. V-model should be enough. If you got some specific case, use the computed
instead.
I think you should get familiar with the custom flow right now. So we will do quickly for the last step.
Normal code: https://github.com/sethsandaru/vue-form-builder/blob/master/src/gui/ui/controls/CheckboxControl.vue
Code for Toggle:
<template>
<div>
<div class="row checkBoxControl" v-if="labelPosition === 'left'">
<div class="col-md-4">
<label :for="control.name + '_gui_control'"
:class="{'bold': control.labelBold, 'italic': control.labelItalic, 'underline': control.labelUnderline}">
{{control.label}}
</label>
</div>
<div class="col-md-8 text-center">
<input type="checkbox"
:readonly="this.control.readonly"
:name="control.fieldName"
v-model="control.value" />
</div>
</div>
<div class="form-group" v-else>
<label :for="control.name + '_gui_control'"
:class="{'bold': control.labelBold, 'italic': control.labelItalic, 'underline': control.labelUnderline}">
{{control.label}}
</label>
<div class="text-center">
<input type="checkbox"
:readonly="this.control.readonly"
:name="control.fieldName"
v-model="control.value" />
</div>
</div>
</div>
</template>
<script>
// REMEMBER: To import your special stuff here :D
require('path/to/my/stuff/bootstrap-toggle.min.js');
require('path/to/my/stuff/bootstrap-toggle.min.css');
export default {
name: "ToggleControl",
props: ['control', 'labelPosition'],
mounted() {
let toggle_state = 'off';
// because the final data for Checkbox/Toggle is true/false also it got default value => set it.
if (this.control.isChecked) {
this.control.value = true;
toggle_state = 'on';
}
$(this.$el).find("input").bootstrapToggle(toggle_state);
},
beforeDestroy() {
// avoid mem leak - destroy it before
$(this.$el).find("input").bootstrapToggle('destroy');
}
}
</script>
Back to this step to see how to define/inject your stuff for the Vue-Form-Builder
Those code below are your friend, look over at it:
- https://github.com/sethsandaru/vue-form-builder/blob/master/src/config/control_constant.js
- https://github.com/sethsandaru/vue-form-builder/tree/master/src/template/ui/common/controls
- https://github.com/sethsandaru/vue-form-builder/tree/master/src/template/ui/sidebar_items
- https://github.com/sethsandaru/vue-form-builder/tree/master/src/gui/ui/controls
Thank you. Sorry for the late documentation.
Copyright © by Seth Phat aka Phat Tran Minh - http://sethphat.com
- Home