Skip to content

Instantly share code, notes, and snippets.

@iErik
Created February 11, 2019 15:43
Show Gist options
  • Select an option

  • Save iErik/b33505e118c4a4bdfa4574d69c49eaeb to your computer and use it in GitHub Desktop.

Select an option

Save iErik/b33505e118c4a4bdfa4574d69c49eaeb to your computer and use it in GitHub Desktop.
<template>
<form class="c-form" name="formData" @submit.prevent="submitForm">
<div class="fields">
<slot>
<template v-for="(field, fieldName) in fields">
<c-radio-button
v-if="['radio', 'check'].includes(field.type)"
class="radio field"
:key="fieldName"
:name="fieldName"
:validation="getValidationMsg(fieldName)"
:options="getFieldOptions(fieldName)"
:value="getFieldValue(fieldName)"
v-bind="field"
@input="updateField(fieldName, $event)"
/>
<c-select
v-else-if="['select'].includes(field.type)"
class="select field"
:key="fieldName"
:name="fieldName"
:label-left="labelLeft"
:disabled="!getFieldOptions(fieldName).length"
:validation="getValidationMsg(fieldName)"
:value="getFieldValue(fieldName)"
:options="getFieldOptions(fieldName)"
v-bind="field"
@input="updateField(fieldName, $event)"
/>
<c-input
v-else
class="field"
:key="fieldName"
:name="fieldName"
:label-left="labelLeft"
:validation="getValidationMsg(fieldName)"
:value="getFieldValue(fieldName)"
v-bind="field"
@input="updateField(fieldName, $event)"
/>
</template>
</slot>
</div>
<div class="actions">
<slot name="actions">
<c-button primary class="action">
Salvar
</c-button>
</slot>
</div>
</form>
</template>
<script>
import CRadioButton from '../CRadioButton'
import CSelect from '../CSelect'
import CInput from '../CInput'
import CButton from '../CButton'
import FormValidator from 'vue-convenia-validator'
export default {
name: 'CForm',
mixins: [ FormValidator ],
components: { CRadioButton, CSelect, CInput, CButton },
props: {
/**
* The form fields.
*/
fields: {
type: [Object],
required: true
},
/**
* Whether the form is loading.
*/
loading: Boolean,
/**
* Disables the form.
*/
disabled: Boolean,
/**
* Moves all of the input's labels to the left side.
*/
labelLeft: Boolean
},
data () {
return {
formData: {}
}
},
methods: {
getValidationMsg (fieldName) {
const fieldDef = this.fields[fieldName]
const fieldFlags = this.$validations[fieldName] || {}
const fieldErrors = (fieldFlags.errors || [])
return fieldErrors.length
? fieldDef.validationMsg || fieldErrors[0] || ''
: ''
},
getFieldValue (fieldName) {
const field = this.fields[fieldName] || {}
if (field.options)
return field.options.find(option => {
return field.trackBy
? option[field.trackBy] === this.formData[fieldName]
: option === this.formData[fieldName]
}) || ''
return this.formData[fieldName]
},
getFieldOptions (fieldName) {
const field = this.fields[fieldName] || {}
return field.optionsFilter
? field.optionsFilter(this.formData, field.options)
: field.options
},
updateField (fieldName, value) {
const field = this.fields[fieldName] || {}
if (field.onInput) field.onInput(this.formData, value)
this.formData[fieldName] = field.trackBy
? value[field.trackBy]
: value
},
submitForm () {
const isValid = this.$validator.validateAll()
if (isValid) this.$emit('submit', this.formData)
}
},
created () {
const reduceToValue = (entity, key, ignoreEmpty) => Object.keys(entity)
.reduce((acc, propName) => ({
...acc,
...(!(entity[propName] || {})[key] && ignoreEmpty
? {}
: { [propName]: (entity[propName] || {})[key] })
}), {})
/*
const reduceToValue = (template, keyName, ignoreEmpty) => Object.keys(template)
.reduce((acc, fieldName) => {
const field = template[fieldName]
const value = (field || {}).trackBy
? field[]
:
const value = (entity[propName] || {})[key]
return {
...acc
...(!value && ignoreEmpty)
}
}, {})
*/
const validations = reduceToValue(this.fields, 'validation', true)
this.formData = reduceToValue(this.fields, 'value')
this.$validator.init({ formData: validations })
}
}
</script>
<style lang="scss">
.c-form {
& > .fields {
& > .field:not(:last-child):not(.-validation) { padding-bottom: 20px; }
// & > .field.-label-left:not(:last-child):not(.-validation) { padding-botom: 20px; }
}
& > .actions {
display: flex;
justify-content: flex-end;
margin-top: 40px;
& > .action {
flex: 1 1;
max-width: 180px;
&:not(:last-child) { margin-right: 10px; }
}
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment