@econnect/webcomponents-library
Documentation
Styleguide
Documentation
Styleguide
  • Getting Started

    • Installation
    • Patch Notes
    • Styleguide
  • Styling

    • e-connect colors
  • UI Components

    • Form

      • Search Field
      • Form Field
      • Forms
    • Filter

      • Filter
      • Search Filter
    • Grid

      • Grid
      • Grid Row
    • Inputs

      • File Input
      • Input Checkbox
      • Input Dropdown
      • Input Date
      • Input Date Time
      • Input Date Time Local
      • Input File
      • Input Label
      • Input Multi Select
      • Input Number
      • Input Radio
      • Input Range
      • Input Select
      • Input Switch
      • Input Slider
      • Input Text
      • Input TextArea
      • Input Time
      • Input Time Range
    • Controls

      • Booleans
      • Button
      • Checkboxes
      • Date Displays
      • Dropdown Lists
      • Text Displays
    • Headers

      • e-header
    • Cards

      • e-card
    • Images

      • Icon
      • Images
      • Flag Image
      • Hamburger
    • Iframe
    • Pager
    • Settings
    • Document Validation
    • Navigation

      • Navigation
      • Navigation Menu
      • Navigation Footer
      • Navigation Button
      • Navigation Button Item
      • Navigation Search Item

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
form json :
title: form-jsonicon: assignmenthasDividers: truesections: []

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>
Last Updated:: 11/1/24, 10:37 AM
Contributors: AzureAD\MarcelLommers, Marcel Lommers
Prev
Search Field
Next
Forms