npm install --save @ianicdev/dataforms
yarn add @ianicdev/dataforms
import Dataforms from "dataforms";
import { extend } from "vee-validate";
import * as rules from "vee-validate/dist/rules";
Vue.use(Dataforms);
Object.keys(rules).forEach((rule) => {
extend(rule, rules[rule]);
});
All the components must have some generic props such as label. The component structure is made of three parts:
- type (ref: Components)
- options (ref: Components Options)
- _validation
- _responsive
Feel free to use any component attributes you should use on vuetify components (such as dark theme, label, hints etc...) Hint: All the generic props that start with underscore (_) are special attributes and doesnt apply to the component. Its used from the library
All available validation rules can be found at https://vee-validate.logaretm.com/v3/guide/rules.html#rules. A custom validation callback is provided from the library using the _callback property
validation: {
_callback() => {
return {
validate: (value) => {
console.log(value);
return true;
},
message: "{_field_} is not valid(?)",
}
}
}
You can specify the grid system via the responsive properties
_responsive: {
sm: 12,
md: 6,
lg: 4,
},
label: "I am a label"
hint: "Write something dude!",
"persistent-hint": true,
1. textField (default) 2. textArea 3. checkBoxes 4. radioButtons 5. fileInput 6. selects 7. selectsAutocomplete
Basic text field
name: {
options: {
label: "First name",
hint: "Είσαι ο;",
"persistent-hint": true,
},
validation: {
required: true,
},
},
Same with text field, a basic textarea component with validation
message: {
type: "textArea",
options: {
label: "Write your message...",
hint: "Write something dude!",
"persistent-hint": true,
},
validation: {
min: 3,
max: 200,
},
},
This component requires an items array with the available options. Also you can set a default value (optional).
terms: {
type: "checkBoxes",
options: {
label: "Terms & conditions",
default: "steal",
hint: "write something here too!",
"persistent-hint": true,
items: [
{
label: "I aggree to steal all my data!",
value: "steal",
},
],
},
validation: {
required: true,
},
},
Radio selects msut have a list property (array) with the available values. You can also provide a default (optional) value
website: {
type: "radioButtons",
options: {
label: "What the of website do you need?",
default: "web_development",
list: [
{
label: "Web design",
value: "web_design",
},
{
label: "Web development",
value: "web_development",
},
{
label: "Logo Design",
value: "logo_design",
},
"Other",
],
},
}
This input acts like normal file input (you should notice the multiple, counter and show-size params) but there are some special rules at validation like mimes or dimensions
yourImage: {
type: "fileInput",
options: {
hint: "write something here too!",
"persistent-hint": true,
label: "Select your image...",
counter: true,
multiple: true,
"show-size": true,
},
validation: {
required: true,
mimes: "image/*",
},
}
deadline: {
type: "selects",
options: {
label: "When do you need this project?",
default: "web_development",
items: [
{
text: "In 1 - 2 Months",
value: "normal_client",
},
{
text: "Now!",
value: "now",
},
{
text: "Yesterday!!!",
value: "yesterday",
},
],
},
},
It behaves like a normal select but you can search inside the list
autocomplete: {
type: "selectsAutocomplete",
options: {
label: "Autocomplete from list",
default: "web_development",
items: [
{
text: "In 1 - 2 Months",
value: "normal_client",
},
{
text: "Now!",
value: "now",
},
{
text: "Yesterday!!!",
value: "yesterday",
},
],
},
validation: {
required: true,
},
},
You should notice that this input doesnt have any Items property but it has an apiUrl. It will lazy load the Items. The response should be an array of objects like the given below [{ text: 'Foo', value: 'Bar' }]
autocomplete: {
type: "selectsAutocomplete",
options: {
label: "Autocomplete from api (fetch once)",
default: "web_development",
apiUrl: "https://api.publicapis.org/entries",
},
validation: {
required: true,
},
}
You should notice the below properties
- isSearchable: enables the type-search feature
- liveSearch: enables the type-search feature
- searchDelay: time in ms that will wait before send the request (usefull when user is typing)
autocomplete: {
type: "selectsAutocomplete",
options: {
label: "Autocomplete from api (live fetching)",
default: "web_development",
apiUrl: "https://api.publicapis.org/entries",
isSearchable: true,
liveSearch: true,
searchDelay: 300,
},
validation: {
required: true,
},
},
After the API Syntax, you should provide a submit property with a click function
submit: {
title: "Send Message",
color: "primary",
click: (formData) => {
this.updateFormResult(formData);
fetch("http://localhost:8080/api/test", requestOptions)
.then((response) => response.json())
.then((data) => console.log(data))
.catch((err) => console.log(err));
Object.keys(formData).forEach((formDataKey) => {
body.append(formDataKey, formData[formDataKey]);
});
alert("Form sent!");
},
},
<template>
<v-app>
<v-main>
<v-container> <Form :api="api" /> </v-container>
<v-container>
<pre>{{ formResult }}</pre>
</v-container>
</v-main>
</v-app>
</template>
<script>
import Form from "@/components/form.vue";
export default {
name: "App",
components: { Form },
methods: {
updateFormResult(formData) {
this.formResult = formData;
},
},
data() {
return {
formResult: {},
api: {
rows: [
{
input: [
{
name: {
options: {
label: "First name",
hint: "Είσαι ο;",
"persistent-hint": true,
},
validation: {
required: true,
},
},
email: {
options: {
default: "support@ianic.gr",
label: "Email",
prependIcon: "mdi-camera",
},
validation: {
required: true,
min: 4,
max: 24,
type: "email",
_callback: () => {
return {
validate: (value) => {
console.log(value);
return true;
},
message: "{_field_} is not valid(?)",
};
},
},
tooltip: {
position: "bottom",
text: "lorem ipsun",
},
},
_responsive: {
sm: 12,
md: 6,
lg: 4,
},
},
{
surname: {
options: {
readonly: true,
label: "Last name",
},
},
phone: {
options: {
loading: true,
label: "Phone",
hint: "Write 'hello' to proceed",
"persistent-hint": true,
},
validation: {
required: true,
is: "hello",
},
tooltip: {
text: "lorem ipsun",
},
},
_responsive: {
sm: 12,
md: 6,
lg: 4,
},
},
],
},
{
input: [
{
deadline: {
type: "selects",
options: {
label: "When do you need this project?",
default: "web_development",
items: [
{
text: "In 1 - 2 Months",
value: "normal_client",
},
{
text: "Now!",
value: "now",
},
{
text: "Yesterday!!!",
value: "yesterday",
},
],
},
},
},
{
autocomplete: {
type: "selectsAutocomplete",
options: {
label: "Autocomplete from list",
default: "web_development",
apiUrl: "https://api.publicapis.org/entries",
items: [
{
text: "In 1 - 2 Months",
value: "normal_client",
},
{
text: "Now!",
value: "now",
},
{
text: "Yesterday!!!",
value: "yesterday",
},
],
},
validation: {
required: true,
},
},
},
],
},
{
input: [
{
autocomplete: {
type: "selectsAutocomplete",
options: {
label: "Autocomplete from api (fetch once)",
default: "web_development",
apiUrl: "https://api.publicapis.org/entries",
},
validation: {
required: true,
},
},
},
{
autocomplete: {
type: "selectsAutocomplete",
options: {
label: "Autocomplete from api (live fetching)",
default: "web_development",
apiUrl: "https://api.publicapis.org/entries",
isSearchable: true,
liveSearch: true,
searchDelay: 300,
},
validation: {
required: true,
},
},
},
],
},
{
input: [
{
website: {
responsive: {},
type: "radioButtons",
options: {
label: "What the of website do you need?",
default: "web_development",
list: [
{
label: "Web design",
value: "web_design",
},
{
label: "Web development",
value: "web_development",
},
{
label: "Logo Design",
value: "logo_design",
},
"Other",
],
},
},
},
],
},
{
input: [
{
message: {
type: "textArea",
options: {
label: "Write your message...",
hint: "Write something dude!",
"persistent-hint": true,
},
validation: {
min: 3,
max: 20,
},
},
},
],
},
{
input: [
{
terms: {
type: "checkBoxes",
options: {
label: "Terms & conditions",
default: "steal",
hint: "write something here too!",
"persistent-hint": true,
items: [
{
label: "I aggree to steal all my data!",
value: "steal",
},
],
},
validation: {
required: true,
},
},
},
],
},
{
input: [
{
yourImage: {
type: "fileInput",
options: {
hint: "write something here too!",
"persistent-hint": true,
label: "Select your image...",
counter: true,
multiple: true,
"show-size": true,
},
validation: {
required: true,
mimes: "image/*",
},
},
},
],
},
],
submit: {
title: "Send Message",
color: "primary",
click: (formData) => {
this.updateFormResult(formData);
/**
* Post in general
*/
const requestOptions = {
method: "POST",
headers: { "Content-Type": "multipart/form-data" },
body: { ...formData },
};
fetch("http://localhost:8080/api/test", requestOptions)
.then((response) => response.json())
.then((data) => console.log("here", data))
.catch((err) => console.log(err));
/**
* Post the form with multipart/form-data or application/x-www-form-urlencoded;charset=UTF-8'
*
let body = new FormData();
Object.keys(formData).forEach((formDataKey) => {
body.append(formDataKey, formData[formDataKey]);
});
const requestOptions = {
method: "POST",
headers: { "Content-Type": "multipart/form-data" },
body,
};
fetch("http://localhost:8080/api/test", requestOptions)
.then((response) => response.json())
.then((data) => console.log("here", data))
.catch((err) => console.log(err));
alert("Form sent!");
},
*/
alert("Form sent!");
},
},
},
value: "",
};
},
};
</script>