Building Reusable Form Components with Compound Components in Vue (TypeScript)
Compound components are a powerful pattern in Vue.js that allow you to create reusable components composed of multiple smaller, specialized components. This challenge focuses on implementing a compound component for building flexible and reusable form input fields, promoting code reusability and maintainability. You'll be creating a FormInput component that can be configured with different input types (text, number, select) and validation rules.
Problem Description
You need to implement a FormInput compound component in Vue.js using TypeScript. This component should encapsulate the logic for rendering different input types, handling user input, and displaying validation errors. The FormInput component will be configurable via props, allowing users to specify the input type, label, model value, and validation rules.
What needs to be achieved:
- Create a
FormInputcomponent that can render different input types (text, number, select). - The component should accept a
modelValueprop to bind to a data property. - The component should accept a
labelprop to display a label for the input field. - The component should accept a
typeprop to specify the input type (e.g., "text", "number", "select"). - The component should accept a
rulesprop to define validation rules (an array of validation functions). - The component should display validation errors if the input is invalid.
- The component should emit an
update:modelValueevent when the input value changes.
Key Requirements:
- Use TypeScript for type safety.
- Implement the compound component pattern effectively, breaking down the component into smaller, manageable parts.
- Handle different input types appropriately (e.g., rendering a
<select>element fortype="select"). - Implement basic validation based on the provided
rules. - Ensure the component is reusable and configurable.
Expected Behavior:
- When the component is initialized, it should render the appropriate input element based on the
typeprop. - When the user interacts with the input field, the
update:modelValueevent should be emitted with the new value. - When the input value is invalid according to the
rules, validation error messages should be displayed below the input field. - The component should update the
modelValueprop when theupdate:modelValueevent is received from a parent component.
Edge Cases to Consider:
- What happens if no
rulesare provided? The input should be considered valid. - What happens if the
typeprop is invalid? Default to a text input. - How should the component handle different validation rule types (e.g., required, minLength, maxLength)?
- Consider how to handle the
v-modelintegration withmodelValueandupdate:modelValue.
Examples
Example 1:
Input:
<FormInput
label="Name"
type="text"
modelValue="John Doe"
rules={[
(value) => !!value || 'Name is required',
(value) => value.length <= 50 || 'Name must be less than 50 characters'
]}
/>
Output:
A text input field with the label "Name", the value "John Doe", and validation errors displayed if the value is empty or longer than 50 characters.
Explanation: The component renders a text input, binds the value to "John Doe", and applies the provided validation rules.
Example 2:
Input:
<FormInput
label="Age"
type="number"
modelValue="25"
/>
Output:
A number input field with the label "Age" and the value "25". No validation rules are applied.
Explanation: The component renders a number input, binds the value to "25", and does not apply any validation rules.
Example 3:
Input:
<FormInput
label="Category"
type="select"
modelValue="option2"
rules={[
(value) => value !== null || 'Category is required'
]}
options={[
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2' },
{ value: 'option3', label: 'Option 3' }
]}
/>
Output:
A select dropdown with the label "Category" and the selected value "option2". An error message is displayed if no option is selected.
Explanation: The component renders a select dropdown, binds the value to "option2", and applies the provided validation rule.
Constraints
- The component must be written in TypeScript.
- The component must be reusable and configurable via props.
- Validation rules should be functions that return an error message string if the input is invalid, or
nullorundefinedif the input is valid. - The component should handle at least
text,number, andselectinput types. - The component should emit the
update:modelValueevent. - The component should display validation errors clearly.
Notes
- Consider using a separate component for rendering the validation errors.
- Think about how to handle different validation rule types in a flexible way.
- The
optionsprop is only relevant for theselectinput type. - Focus on creating a clean and well-structured component that is easy to understand and maintain.
- This is a good opportunity to practice using Vue's reactivity system and prop drilling.
- Remember to handle the
v-modelintegration correctly usingmodelValueandupdate:modelValue.