# Componente

# Introducción

Este componente renderizará un input de tipo text field. El mismo se compone de dos partes, una de renderizado y otra de lógica (IrTextField Bone), esta ultima será la encargada de el manejo de los datos.

# Uso

Es importante recalcar el nombre del componente IrTextField a nivel de código, ya que este deberá usarse para llamar al componente para renderizarlo, ya sea individiualmente o en un IrForm.

# Ejemplo

# Propiedades

Propiedad Tipo Default Descripción
readonly Boolean

false

El valor readonly = true, establecerá al campo como solo lectura.

linked String | Boolean

false

Determina la actualización del formulario contenedor cuando se cambia de valor del componente. Valores posibles: 'replace' 'update' false true. En caso de ser update el formulario refrescará únicamente el campo modificado. Aquí se explica mejor su funcionamiento.

value String

String que almacenará los valores ingresados en el componente.

required Boolean

false

En valor true, define que el componente debe ser valorizado para ser válido.

placeholder String

''

Establece el placeholder en el campo.

pattern String

''

Un String que defina una expresión regular que deberá cumplir el input para ser válido. En caso de no poderse enviar \ desde la capa de datos, enviese ~, ICL lo tomará como \ en su lugar.

hint Object | String

''

Genera un texto de ayuda para el componente, que podrá ser o no, clickeable para navegar a un link determinado. En el caso de que se envíe un hint, la propiedad hide-details se validará con true.

Propiedad con estructura de objeto con los siguientes keys:

{
  link: String,
  text: String
  openNewTab:Boolean
  classes:String
}

En la propiedad text del objeto se determinará el texto que mostrará el hint, esta propiedad debe estar valorizada para que se muestre el hint.

En la propiedad link del objeto se determinará el link al cual navegará al clickear en el hint, si no se encuentra valorizada el hint no será clickeable, solo será texto.

En la propiedad openNewTab del objeto se determinará si al clickearse el hint con link valorizado, se navegará en una nueva pestaña. Solo es útil paracuando la propedad link del objeto está definida. Si no se encuentra definido, se navegará en la misma pestaña.

En la propiedad classes del objeto, se determinarán las clases que se aplicarán al hint, las clases serán separadas por un espacio, sirven para definir estilos. Se utilizarán principalmente clases de vuetify.

Las clases aplicables para las filas de la tabla podrán encontrarse en Vuetify en los siguientes enlaces:

mask String
  ''

Determina un formato que cumplirá el texto introducido en el campo. Por ejemplo siendo mask = "999-999" el valor ingresado se forzará a ser algo como 333-333. El patron se define con los siguientes 3 caracteres: 9 para números, A para letras y S para alfanuméricos. El resto de los caracteres ingresados será tomado como tal.

money Object
  {}

Determina un formato que cumplirá el valor introducido en el campo. Este formato será definido por:

{
  // Decimal precision -> "90"
  precision: 2,
  // Decimal separator -> ",90"
  separator: ',',
  // Thousand delimiter -> "12.345.678"
  delimiter: '.',
  // Money unit -> "R$ 12.345.678,90"
  unit: 'R$',
  // Money unit -> "12.345.678,90 R$"
  suffixUnit: 'R$',
  // Force type only number instead decimal,
  // masking decimals with ",00"
  // Zero cents -> "R$ 1.234.567.890,00"
  zeroCents: true
}

# Código fuente

<template>
  <ir-text-field-bone
    v-bind="$attrs"
    :value="value"
    v-on="$listeners"
    @input="(e) => $emit('input', e)"
  >
    <div
      slot-scope="{
        inputEvents,
        placeholder,
        vallocal,
        readonly,
        rules,
        hideDetails,
        label,
        comportamientos,
        comportamientosPositions,
        valueType,
        id_resolver,
        comportamientoEvents,
        disabled,
        linked,
        maskHandler
      }"
    >
      <ir-label
        v-if="isOutlined"
        :label="label"
        :error="hasError"
        :disabled="disabled"
        :readonly="readonly"
      />
      <v-text-field
        ref="irTextFieldDOM"
        v-model="vallocal"
        type="text"
        :name="'text-field-' + label"
        class="pt-0 align-center"
        v-bind="getFilteredProps"
        :placeholder="placeholder"
        :hide-details="hideDetails"
        :rules="rules"
        :readonly="readonly"
        :label="isOutlined ? undefined : label"
        :disabled="readonly || disabled"
        @input="maskHandler($event, irTextFieldDOM)"
        @blur="emitLinked(linked, comportamientoEvents['change-linked-value'])"
        @update:error="setError"
        @keydown.enter.prevent="
          enterManager(
            comportamientos,
            linked,
            comportamientoEvents['change-linked-value']
          )
        "
        v-on="inputEvents"
      >
        <template #message="{ message }">
          <div v-html="message" />
        </template>
        <template
          v-for="(position, k) in comportamientosPositions"
          #[position]
        >
          <div
            :key="'slot-comportamientos-tf-' + k"
            class="d-flex align-center"
            style="gap: 10px"
          >
            <template v-for="(comportamiento, i) in comportamientos">
              <ir-comportamiento
                v-if="
                  (typeof comportamiento.visible === 'undefined' ||
                    comportamiento.visible) &&
                  comportamiento.position === position
                "
                :key="'comportamiento-textfield-' + i"
                :ref="'comportamiento' + i"
                v-bind="comportamiento"
                :value="vallocal"
                :value_type="valueType"
                :father_component_name="textFieldComponentName"
                :current_id_resolver="id_resolver"
                v-on="comportamientoEvents"
              />
            </template>
          </div>
        </template>
        <template
          v-if="readonly && !localValue"
          #prepend-inner
        >
          <div class="pr-2">
            <v-icon color="warning"> mdi-alert-circle </v-icon>
          </div>
        </template>
      </v-text-field>
    </div>
  </ir-text-field-bone>
</template>

<script>
import { ref, watch, onMounted, computed } from 'vue'
import IrTextFieldBone from './IrTextFieldBone.vue'
import { textFieldComponentName } from '../../../constants'
import { setHintTag } from '../../../helpers/hint'
import { isOutlined } from '../../../helpers/utils.js'
import focusAndScrollMixin from '../../../mixins/focusAndScroll'
import { filterProps } from '../../../helpers/filterProps'
export default {
  name: textFieldComponentName,
  components: {
    IrTextFieldBone
  },
  inheritAttrs: false,
  props: {
    value: {
      type: String,
      required: true
    },
    isFocused: {
      type: Boolean,
      default: false
    },
    hint: {
      type: [String, Object],
      default: ''
    }
  },
  setup(props, { emit, attrs }) {
    const { focusAndScroll } = focusAndScrollMixin.methods
    const isOutlinedHelper = isOutlined
    const irTextFieldDOM = ref(null)
    const comportamiento0 = ref(null) // Declaración de const para ref del DOM, no cambiar nombre.
    const localValue = ref(props.value)
    const otherProps = ref({})
    const hasError = ref(false)
    const previousValue = ref(props.value)

    const filteredProps = filterProps(irTextFieldDOM.value, otherProps, [
      'data-cy'
    ])

    const updateLocalValue = (value) => {
      localValue.value = value
      emit('input', value)
    }
    const emitLinked = (linked, linkedEvent) => {
      const isDifferentValue = previousValue.value !== props.value
      previousValue.value = props.value
      if (linked && linkedEvent && isDifferentValue) {
        linkedEvent()
      }
    }

    const enterManager = (comportamientos, linked, linkedEvent) => {
      const isComps = comportamientos ? comportamientos.length === 1 : false
      const comp = isComps ? comportamiento0.value : null
      if (comp && comp[0] && comp[0].clickComportamiento) {
        comp[0].clickComportamiento()
      } else {
        emitLinked(linked, linkedEvent)
      }
    }

    const setError = (eventValue) => {
      hasError.value = eventValue
    }

    watch(localValue, (newValue) => {
      emit('input', newValue)
    })

    watch(
      () => props.value,
      (newValue) => {
        localValue.value = newValue
      }
    )

    onMounted(() => {
      if (props.isFocused) {
        const element = irTextFieldDOM.value.$el.querySelector('input')
        focusAndScroll(element)
      }
      otherProps.value = { ...attrs.props }
      if (otherProps.value.hint && typeof otherProps.value.hint === 'string') {
        otherProps.value['hide-details'] = false
      }
    })

    const isOutlinedLocal = computed(() => {
      return isOutlinedHelper(otherProps.value.outlined)
    })

    const handledAttrs = computed(() => {
      const hint = setHintTag(otherProps.value, props.hint)
      let aux = { ...otherProps.value, ...attrs }
      delete aux.hint
      if (hint) {
        aux = { ...aux, hint }
      }
      delete aux.placeholder
      delete aux.readonly
      delete aux.rules
      delete aux.pattern
      delete aux.required
      delete aux.value
      delete aux.type
      delete aux.label
      delete aux.name
      return aux
    })

    const getFilteredProps = computed(() => {
      return filterProps(irTextFieldDOM.value, handledAttrs.value, ['data-cy'])
    })

    return {
      textFieldComponentName,
      localValue,
      irTextFieldDOM,
      filteredProps,
      hasError,
      updateLocalValue,
      emitLinked,
      enterManager,
      setError,
      isOutlined: isOutlinedLocal,
      handledAttrs,
      getFilteredProps,
      comportamiento0
    }
  }
}
</script>

<style scoped lang="scss"></style>
Last Updated: 7/25/2025, 8:09:18 PM