e-schultz / vue-dynamic-components

Exploring Dynamic Components with Vue
77 stars 21 forks source link

How to migrate dynamic components to Vue 3? #6

Open Olafxso opened 2 years ago

Olafxso commented 2 years ago

Hi,

I am using your FormGenerator example in my application. Thanks for sharing this code! Now I want to migrate to Vue3 and I cannot figure out how to get the FormGenerator working.

This is what I have got so far:

<template>
  <div>
    <component v-for="(field, index) in schema"
               :key="index"
               :is="field.fieldType"
               :value="formData[field.name]"
               @input="updateForm(field.name, $event)"
               v-bind="field">
    </component>
  </div>
</template>

<script>
import NumberInput from "./NumberInput";
import SelectList from "./SelectList";
import TextInput from "./TextInput";
export default {
  name: "FormGenerator",
  components: { NumberInput, SelectList, TextInput },
  props: ["schema", "modelValue"],  // changed form value to modelValue
  data() {
    return {
      // changed form value to modelValue
      //formData: this.value || {}
      formData: this.modelValue || {}
    };
  },
  methods: {
    updateForm(fieldName, value) {
      // changed for updating the field of the given modelValue
      //this.$set(this.formData, fieldName, value);
      //this.$emit("input", this.formData);
      this.$emit("update:modelValue", { ...this.formData, fieldName: value });
    }
  }
};
</script>

I have changed the prop value to modelValue and also changed the formData. But the value is not show in the component. I think this is might not valid in Vue 3 :value="formData[field.name]" What do you think?

I managed it to migrate the components itself. Do you have got an idea how to migrate this? I really appreciate it if you could help me.

Regards Olaf.

Olafxso commented 2 years ago

I want to let you know I got it working now. I must use :modelValue and @update:modelValue. This is my FormGenerator now:

<template>
  <div>
    <component v-for="(field, index) in schema"
               v-bind="field"
               :key="index"
               :is="field.fieldType"               
               :modelValue="formData[field.fieldName]"
               @update:modelValue="updateForm(field.fieldName, $event)">
    </component>
  </div>
</template>

<script>
import NumberInput from "./NumberInput";
import SelectList from "./SelectList";
import TextInput from "./TextInput";
export default {
  name: "FormGenerator",
  components: { NumberInput, SelectList, TextInput },
  props: ["schema", "modelValue"],  // changed form value to modelValue
  data() {
    return {
      // changed form value to modelValue
      //formData: this.value || {}
      formData: this.modelValue || {}
    };
  },
  methods: {
    updateForm(fieldName, value) {
      // changed for updating the field of the given modelValue. $set is not allowed any more
      //this.$set(this.formData, fieldName, value);      
      var newObject = { ...this.formData };
      // trigger only when changes
      if (newObject[fieldName] !== value) {
        newObject[fieldName] = value;
        this.$emit("update:modelValue", newObject);
      }      
    }
  }
};
</script>