Vue Select Binding with TypeScript
This challenge focuses on implementing a two-way data binding for a select element in a Vue.js application using TypeScript. Two-way binding allows changes in the select element to update a data property in the Vue component, and vice versa, ensuring the UI and data remain synchronized. This is a fundamental concept in Vue and crucial for building interactive user interfaces.
Problem Description
You are tasked with creating a reusable Vue component that provides two-way data binding for a select element. The component should accept the following props:
modelValue: (string | number | null) - The currently selected value. This is the value that will be bound to the component's data. It can be a string, number, or null.options: (Array<{label: string, value: string | number}>) - An array of objects, where each object represents an option in the select element. Each option object must have alabel(string) and avalue(string or number) property.labelKey: (string) - The key to use for the label in the options. Defaults to 'label'.valueKey: (string) - The key to use for the value in the options. Defaults to 'value'.
The component should emit an update:modelValue event whenever the selected option changes. This event should carry the new value of the selected option.
Key Requirements:
- Implement two-way data binding between the
modelValueprop and the select element's selected value. - Render the
optionsarray as<option>elements within the select element. - Ensure that the currently selected option's
valuematches themodelValueprop. - Handle the case where
modelValueisnullorundefined(no option is selected). - Use TypeScript for type safety.
Expected Behavior:
- When the component is initialized, the select element should display options based on the
optionsprop. - The initially selected option should be the one whose
valuematches themodelValueprop. IfmodelValueis null/undefined, no option should be selected. - When the user selects a different option from the select element, the
update:modelValueevent should be emitted with thevalueof the selected option. - When the
modelValueprop changes externally, the select element should update to reflect the new selected value.
Edge Cases to Consider:
- Empty
optionsarray: The select element should be empty. modelValuenot present in any option'svalue: No option should be selected.optionsarray contains duplicatevalues: The behavior is undefined, but the component should not crash. Ideally, only the first matching option should be selected.
Examples
Example 1:
Input:
options = [{label: 'Option 1', value: 1}, {label: 'Option 2', value: 2}]
modelValue = 1
Output:
<select>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select>
Explanation: The select element displays two options, and "Option 1" is pre-selected because its value (1) matches the modelValue.
Example 2:
Input:
options = [{label: 'Red', value: 'red'}, {label: 'Green', value: 'green'}]
modelValue = 'blue'
Output:
<select>
<option value="red">Red</option>
<option value="green">Green</option>
</select>
Explanation: The select element displays two options, and no option is selected because the modelValue ('blue') does not match any of the option values.
Example 3:
Input:
options = []
modelValue = 5
Output:
<select>
</select>
Explanation: The select element is empty because the options array is empty.
Constraints
- The component should be written in Vue 3 with the Composition API.
- The component should be written in TypeScript.
- The component should be reusable and accept the specified props.
- The component should emit the
update:modelValueevent correctly. - The component should handle edge cases gracefully.
- The component should be reasonably performant (rendering a large number of options should not cause significant performance issues). Assume a maximum of 100 options.
Notes
- Consider using the
v-modeldirective to simplify the two-way data binding. - Pay close attention to the type definitions for the props and emitted event.
- Think about how to handle the case where the
modelValueis not found in theoptionsarray. - This is a fundamental building block for many Vue applications, so focus on creating a clean, well-documented, and reusable component.