Vue 3.2 Select changes subsequent select

86 views Asked by At

I have two selects, material and color1. I want to change options of color1 element when material is changed. Here's what I have so far:

Script setup:

const data = ref({
    materialType: 'none',
    colors: MyData.MaterialColors['none']
});

const chgMatl = ($event) => {
    data.materialType = $event.target.value
    data.colors = MyData.MaterialColors[data.materialType];
    return data.colors
}

Vue Template:

<FormKit v-model="data.materialType" @change="chgMatl($event)" type="select" name="material" label="Material" validation="required" :options="MyData.Materials"></FormKit>
<FormKit type="select" name="color1" label="Color" validation="required" :options="data.colors"></FormKit>

Sample MyData.MaterialColors:

{
   a: { 1: '1', 2: '2', 3: '3' },
   b: { 1: '1', 2: '2', 3: '3' },
   c: { 1: '1', 2: '2', 3: '3' }
}

When MyData.Materials is changed, it's value is a. This sets data.materialType = a, which plugs into MyData.MaterialColors[a] and returns { 1: '1', 2: '2', 3: '3' } which then populates the colors element's :options.

I was able to make this work alternatively by putting MyData.MaterialColors directly into :options. The dependent select element worked as required. However, the HTML element did not like having brackets [] in the :options field so it would not process properly. I could tell because the closing FormKit tag was red and angry. The view worked when Material changed, but model output did not save to the database.

<FormKit type="select" name="color1" label="Color" validation="required" :options="MyData.MaterialColors[data.materialType]"></FormKit>

Is there a way to have data in the options field with brackets, or can this be represented another way that will produce the necessary information? Or is there a way to set the options directly from the chgMatl function, like jQuery $('#color1').val()? I'm open to a solution from any possibility. Thanks!

2

There are 2 answers

0
Jaromanda X On BEST ANSWER

In your script, (assuming <script setup>)

The main point is to crate a colorList computed that returns the appropriate color list

The watch is there to clear the color selection when the material is changed

<script setup>
  import { ref, computed, watch } from "vue";
  const materialType = ref("");
  const selectedColor = ref("");
  const colorList = computed(() => MyData.MaterialColors[materialType.value] ?? {});
  watch(materialType, () => (selectedColor.value = ""));
</script>

and in the template

<FormKit v-model="materialType" type="select" name="material" label="Material" validation="required" :options="MyData.Materials"></FormKit>
<FormKit v-model="selectedColor" type="select" name="color1" label="Color" validation="required" :options="colorList"></FormKit>
0
Eliseo On

You are using Vue 3 with the Composition API, and you want to dynamically change the options of the second <FormKit> select based on the selected value of the first select. Your approach is on the right track, but you need to make sure that the reactivity system of Vue is properly triggered when you update data.materialType and data.colors.

Here's a modified version of your code:

html:

<template>
  <div>
    <FormKit v-model="data.materialType" @change="chgMatl" type="select" name="material" label="Material" validation="required" :options="MyData.Materials"></FormKit>
    <FormKit v-model="selectedColor" type="select" name="color1" label="Color" validation="required" :options="colorOptions"></FormKit>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue';

const data = ref({
    materialType: 'none',
    colors: MyData.MaterialColors['none']
    });

const selectedColor = ref(data.colors[Object.keys(data.colors)[0]]); // Initial selected color

const chgMatl = () => {
  data.colors = MyData.MaterialColors[data.materialType];
  selectedColor.value = data.colors[Object.keys(data.colors)[0]]; // Reset selected color
}

const colorOptions = ref([]);
watch(() => data.colors, () => colorOptions.value = Object.entries(data.colors).map(([key, value]) => ({ value: key, text: value })));
</script>

In this modification, I've added a selectedColor ref to hold the selected color, and I've initialized it to the first color in the data.colors object. I also added a colorOptions ref that is updated whenever data.colors changes. This ensures that the second <FormKit> select's options are reactive and will update accordingly.

The chgMatl function now resets the selected color to the first color in the updated data.colors object.

Now, the <FormKit> for the color should correctly update its options and the selected color based on the changes in the first select.