title: form-jsonicon: assignmenthasDividers: truesections: []
Form Field v1.0
The <e-form-field> component is a component that can be used for .
Usage
An e-form-field has attributes that must be provided,
<e-form-field
:model="fieldData"
/>
Attributes
model | Type: EFormFieldModel | required
type | Type: EFormFieldType | required
id | Type: String | required
value | Type: String | Default:''
label | Type: String | Default:''
placeholder | Type: String | Default:''
required | Type: Boolean | Default:false
hidden | Type: Boolean | Default:false
options | Type: EFormFieldOptionType[] | Default:[]
meta | Type: Object | Default:'{ disabled: false }'
const testData = {
type: 'text',
id: 'test',
value: '',
label: 'test field label',
placeholder: 'test placeholder',
required: true,
hidden: false,
meta: {
options: []
},
options: []
}
const selectOptions = [
{
id: 0,
text: 'Example Option 1',
value: 'exampleOption1',
description: '',
disabled: false
},
{
id: 1,
text: 'Example Option 2',
value: 'exampleOption2',
description: '',
disabled: false
}
]
Examples
Below a few interactive examples of e-form-field can be found.
Default
<e-form-field
id='text-field'
:model="testData"
/>
Sandbox
uses default input: false
Source Code
e-form-field.vue
<script setup lang="ts">
import { computed, ref } from 'vue';
import { Dictionary, EFormFieldModel, EFormFieldType, ValueUpdate } from 'types';
import EInputButton from '../e-input-button/e-input-button.vue';
import ECheckbox from '../e-checkbox/e-checkbox.vue';
import EInputDate from '../e-input-date/e-input-date.vue';
import EInputDateTime from '../e-input-date-time/e-input-date-time.vue';
import EInputDateTimeLocal from '../e-input-date-time-local/e-input-date-time-local.vue';
import EInputDropdown from '../e-input-dropdown/e-input-dropdown.vue';
import EInputFile from '../e-input-file/e-input-file.vue';
import EInputLabel from '../e-input-label/e-input-label.vue';
import EInputMultiSelect from '../e-input-multi-select/e-input-multi-select.vue';
import EInputNumber from '../e-input-number/e-input-number.vue';
import EInputRadio from '../e-input-radio/e-input-radio.vue';
import EInputRange from '../e-input-range/e-input-range.vue';
import EInputSelect from '../e-input-select/e-input-select.vue';
import EInputSlider from '../e-input-slider/e-input-slider.vue';
import EInputSwitch from '../e-input-switch/e-input-switch.vue';
import EInputText from '../e-input-text/e-input-text.vue';
import EInputTextarea from '../e-input-textarea/e-input-textarea.vue';
import EInputTime from '../e-input-time/e-input-time.vue';
import EInputTimeRange from '../e-input-time-range/e-input-time-range.vue';
export type Props = {
model: EFormFieldModel;
};
const props = withDefaults(defineProps<Props>(), {});
const emit = defineEmits<{
(e: 'blur', event: FocusEvent): void;
(e: 'keyup.enter', event: KeyboardEvent): void;
(e: 'emit:validity', value: ValueUpdate): void;
(e: 'emit:value', value: ValueUpdate): void;
(e: 'emit:search', value: ValueUpdate): void;
}>();
const input = ref<HTMLInputElement>();
const fieldType = computed(() => {
return props.model.type as string;
});
const fieldMeta = computed(() => {
return (props.model.meta || {}) as Dictionary;
});
const canAutoComplete = computed(() => {
switch (fieldMeta.value?.['autoComplete']) {
case true:
case 'on':
// Prevent filling in password for new users.
return 'new-password';
case false:
case 'off':
default:
return 'off';
}
});
const builtInLabelInputList = ref([EFormFieldType.Label, EFormFieldType.TimeRange]);
const hasBuiltInLabel = computed(() => {
return builtInLabelInputList.value.includes(fieldType.value);
});
function emitUpdate(event: Event): void {
const target = event.target as HTMLInputElement;
let newValue = target.type === 'checkbox' ? target.checked : target.value;
emitValue(newValue);
}
function emitValidity(newValue: boolean): void {
emit('emit:validity', { key: props.model.id, newValue: newValue } as ValueUpdate);
}
function emitValue(newValue: unknown): void {
emit('emit:value', { key: props.model.id, newValue: newValue } as ValueUpdate);
}
function emitSearch(newValue: string): void {
emit('emit:search', { key: props.model.id, newValue: newValue } as ValueUpdate);
}
const timer = ref<NodeJS.Timeout>();
function debounceEmit(event: Event, msDelay: number = 500): void {
clearTimeout(timer.value);
timer.value = setTimeout(() => {
emitUpdate(event);
}, msDelay);
}
</script>
<template>
<div
v-show="!model.hidden"
class="e-form-field"
:class="{
required: model.required
}"
>
<e-input-label
v-if="!hasBuiltInLabel && model?.label"
:id="model.id"
class="field-label"
:class="{
clickable: fieldType !== EFormFieldType.Radio
}"
:value="model?.label"
/>
<e-input-label
v-if="fieldType === EFormFieldType.Label"
:id="model.id"
:value="model.value"
/>
<e-input-button
v-else-if="fieldType === EFormFieldType.Button"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
@blur="emit('blur', $event)"
@keyup.enter="emit('keyup.enter', $event)"
/>
<e-checkbox
v-else-if="fieldType === EFormFieldType.Checkbox"
:id="model.id"
:name="model.id"
:value="model.value === 'true'"
:label="model?.label || model.placeholder"
:type="model.type"
:required="model.required"
:disabled="fieldMeta['disabled'] || false"
@update:value="emitValue"
/>
<e-input-date
v-else-if="fieldType === EFormFieldType.Date"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
@blur="emit('blur', $event)"
@keyup.enter="emit('keyup.enter', $event)"
/>
<e-input-date-time
v-else-if="fieldType === EFormFieldType.DateTime"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
@blur="emit('blur', $event)"
@keyup.enter="emit('keyup.enter', $event)"
/>
<e-input-date-time-local
v-else-if="fieldType === EFormFieldType.DateTimeLocal"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:validity="emitValidity"
@update:value="emitValue"
@blur="emit('blur', $event)"
@keyup.enter="emit('keyup.enter', $event)"
/>
<e-input-dropdown
v-else-if="fieldType === EFormFieldType.Dropdown"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:options="model.options"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
@update:search="emitSearch"
/>
<e-input-file
v-else-if="fieldType === EFormFieldType.File"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
/>
<e-input-radio
v-else-if="fieldType === EFormFieldType.Radio"
:id="model.id"
:name="model.id"
:value="model.value"
:options="model.options"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
/>
<e-input-range
v-else-if="fieldType === EFormFieldType.Range"
:id="model.id"
:name="model.id"
:value="model.value"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
/>
<e-input-select
v-else-if="fieldType === EFormFieldType.Select"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:options="model.options"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
@update:search="emitSearch"
/>
<e-input-multi-select
v-else-if="fieldType === EFormFieldType.MultiSelect"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:options="model.options"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
@update:search="emitSearch"
/>
<e-input-number
v-else-if="fieldType === EFormFieldType.Number"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
@blur="emit('blur', $event)"
@keyup.enter="emit('keyup.enter', $event)"
/>
<e-input-slider
v-else-if="fieldType === EFormFieldType.Slider"
:id="model.id"
:name="model.id"
:value="model.value"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
/>
<e-input-switch
v-else-if="fieldType === EFormFieldType.Switch"
:id="model.id"
:name="model.id"
:checked="model.value === 'true'"
:placeholder="model.placeholder || model?.label"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
/>
<e-input-text
v-else-if="fieldType === EFormFieldType.Text"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
@blur="emit('blur', $event)"
@keyup.enter="emit('keyup.enter', $event)"
/>
<e-input-textarea
v-else-if="fieldType === EFormFieldType.TextArea"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
@blur="emit('blur', $event)"
@keyup.enter="emit('keyup.enter', $event)"
/>
<e-input-time
v-else-if="fieldType === EFormFieldType.Time"
:id="model.id"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
@blur="emit('blur', $event)"
@keyup.enter="emit('keyup.enter', $event)"
/>
<e-input-time-range
v-else-if="fieldType === EFormFieldType.TimeRange"
:id="model.id"
:name="model.id"
:label="model?.label"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:options="model.options"
:type="model.type"
:required="model.required"
:meta="fieldMeta"
@update:value="emitValue"
@blur="emit('blur', $event)"
@keyup.enter="emit('keyup.enter', $event)"
/>
<input
v-else
:id="model.id"
ref="input"
class="e-form-field-fallback"
:name="model.id"
:value="model.value"
:placeholder="model.placeholder || model?.label"
:type="model.type"
:required="model.required"
:autocomplete="canAutoComplete"
:disabled="fieldMeta.disabled"
@input="debounceEmit($event, 500)"
@change="debounceEmit($event, 500)"
@blur="emit('blur', $event)"
@keyup.enter="emit('keyup.enter', $event)"
/>
</div>
</template>
<style scoped lang="scss">
.e-form-field {
display: flex;
flex-direction: column;
width: 100%;
gap: 10px;
.field-label {
line-height: var(--e-body-font-line-height);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&.clickable {
cursor: pointer;
}
}
&.required {
.field-label {
&::after {
content: '*';
padding-left: 2px;
color: var(--e-required);
font-weight: bold;
}
}
}
input {
&.e-form-field-fallback {
border: none;
padding: 15px;
background-color: var(--e-input-background);
font: normal normal normal 16px/20px var(--e-body-font-family);
border-radius: 15px;
color: var(--e-body-font-color);
}
&:focus {
background-color: var(--e-input-focus-background);
}
&[type='color'] {
padding: 2px;
border-radius: 5px;
}
&[type='range'] {
padding: 0;
}
&::placeholder {
color: var(--e-gray-300);
}
&[required] {
+ label::after {
content: '*';
padding-left: 2px;
color: var(--e-required);
font-weight: bold;
}
}
}
&.spacing {
min-width: 60%;
}
}
</style>