Home > front end >  Reusable input component with vue 3 typescript composition api
Reusable input component with vue 3 typescript composition api

Time:11-30

I have the following (atom) input component Element UI (Element Plus for vue 3) as base component.

atom/input/index.vue

<template>
  <el-form-item :label="label">
    <ElInput
      :value="modelValue"
      @input="$emit('update:modelValue', handleInputChange($event))"
    >
      <template v-if="prepend" #prepend>Http://</template>
      <template v-if="append" #append>.com</template>
    </ElInput>
  </el-form-item>
</template>
<script setup lang="ts">
  import { ElInput, ElFormItem } from "element-plus"
  interface IInput {
    label: string
    modelValue: any
  }
  const { label, modelValue } = defineProps<IInput>()

  const handleInputChange = (event: Event) => {
    console.log(event)
    return (event.target as HTMLInputElement).value
  }
</script>

In my home component:

components/home.vue

<template>
  <Input :label="'Book title'" v-model="title" />
<br/>
<h1>{{title}}</h1>
</template>
<script setup lang="ts">
  import { ref } from "vue"
  import Input from "./atom/input/index.vue"
  const title = ref<string>("")
</script>

With the above code setup the component is displayed in correct form with its label.

But when I start typing in the input component I get the following error in my console.

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'value')

I've also logged the event in the console and it is returning the characters that I've typed.

Additionally I get error message of:

Argument of type 'string' is not assignable to parameter of type 'Event'.

In my code line : @input="$emit('update:modelValue', handleInputChange($event))"

Which I was able to remove my typecasting: handleInputChange(<Event | unknown>$event)

I also tried creating reusable input component with html input tag with same value and emit as above and it worked without any error.

Can anyone help me figure out what I'm missing here ?

Update:

As suggestion by Duannx I changed my return of the function:

  const handleInputChange = (event: any) => {
    return event
  }

But now when I type in the input field the first character is replaced by second character, second character is replaced by third and so on.

Here is the reproduction of the issue in element ui playground:

Demo url

CodePudding user response:

The input event of the element plus input is passed a value (string | number), not an Event type. So you can use $event directly as the value.

<ElInput
      :value="modelValue"
      @input="$emit('update:modelValue', $event)"
>
      <template v-if="prepend" #prepend>Http://</template>
      <template v-if="append" #append>.com</template>
</ElInput>

CodePudding user response:

I figured out that I have to make use of set and get method in computed property.

<template>
  <el-form-item :label="label">
    <ElInput
      :autofocus="true"
      :type="type"
      :placeholder="placeholder"
      :show-word-limit="showWordLimit"
      :clearable="clearable"
      :show-password="showPassword"
      :suffix-icon="suffixIcon"
      :prefix-icon="prefixIcon"
      :size="size"
      :max-length="maxLength"
      :value="modelValue"
      @input="$emit('update:modelValue', handleInputChange($event))"
    >
      <template v-if="prepend" #prepend>Http://</template>
      <template v-if="append" #append>.com</template>
    </ElInput>
  </el-form-item>
</template>
<script setup lang="ts">
  import { ElInput, ElFormItem } from "element-plus"
  interface IInput {
    label: string
    type?: string
    placeholder?: string
    maxLength?: number
    showWordLimit?: boolean
    clearable?: boolean
    showPassword?: boolean
    suffixIcon?: any
    prefixIcon?: any
    size?: string
    prepend?: any
    append?: any
    modelValue: any
  }
  const {
    label,
    type,
    placeholder,
    maxLength,
    showWordLimit,
    clearable,
    showPassword,
    suffixIcon,
    prefixIcon,
    size,
    prepend,
    append,
    modelValue,
  } = defineProps<IInput>()

  const handleInputChange = (value: any) => {
    return value
  }

</script>
  • Related