Building a Controlled Input Component in Vue with TypeScript
This challenge focuses on creating a reusable, controlled input component in Vue.js using TypeScript. Controlled components are crucial for managing form data effectively and ensuring predictable behavior, especially when dealing with complex validation or external data sources.
Problem Description
You are tasked with building a ControlledInput component that allows users to input text and updates a parent component's data in real-time. The component should accept a modelValue prop (representing the initial value and the data source) and emit an update:modelValue event whenever the input changes. The component should also accept a type prop to specify the input type (e.g., "text", "number", "email"). Proper TypeScript typing is essential for code clarity and maintainability.
Key Requirements:
modelValueProp: The component must accept amodelValueprop of typestring. This prop represents the current value of the input and the data source that the component will update.update:modelValueEvent: The component must emit anupdate:modelValueevent whenever the input value changes. The event payload should be the new input value.typeProp: The component must accept atypeprop of typestringto specify the input type. Default to "text" if no type is provided.- Two-Way Binding: The component should effectively implement two-way data binding, where changes in the input field update the
modelValueprop in the parent component. - TypeScript: The component must be written in TypeScript with appropriate type annotations for props, events, and internal variables.
Expected Behavior:
- When the component is initialized, the input field should display the value of the
modelValueprop. - As the user types in the input field, the
update:modelValueevent should be emitted with the current input value. - The parent component should listen for the
update:modelValueevent and update its data accordingly. - The input type should be set according to the
typeprop.
Edge Cases to Consider:
- Initial
modelValuebeing an empty string. typeprop being an invalid value (handle gracefully, defaulting to "text").- The parent component not providing a
modelValue. (Consider providing a default value or throwing a warning).
Examples
Example 1:
Input:
Parent Component: data = { message: "Hello" }
ControlledInput component with modelValue="message"
Output:
Input field displays "Hello". When the user types "World", the parent component's data.message is updated to "World".
Explanation: The input field is initially bound to the parent's data. User input updates the parent's data.
Example 2:
Input:
Parent Component: data = { username: "" }
ControlledInput component with modelValue="username" and type="email"
Output:
Input field displays an empty string. The input field is of type "email". When the user types "test@example.com", the parent component's data.username is updated to "test@example.com".
Explanation: The input field is initially bound to the parent's data. The input type is set to email. User input updates the parent's data.
Example 3: (Edge Case)
Input:
Parent Component: data = { name: undefined }
ControlledInput component with modelValue="name"
Output:
Input field displays an empty string. The parent component's data.name is updated with the input value.
Explanation: Handles undefined initial value gracefully by defaulting to an empty string.
Constraints
- The component must be a single-file Vue component (.vue file).
- The component must be written in TypeScript.
- The component should be reusable and easily integrated into other Vue components.
- The component should not have any external dependencies beyond Vue and TypeScript.
- The component should be reasonably performant (avoid unnecessary re-renders).
Notes
- Consider using
v-modelin the parent component to simplify the data binding process. - Think about how to handle potential errors or invalid input values. While validation isn't explicitly required, consider how the component could be extended to support it.
- Focus on creating a clean, well-documented, and maintainable component.
- Remember that
modelValueis the prop andupdate:modelValueis the event. Thev-modeldirective in the parent component automatically handles these.