vue.jsvuejs3vue-componentvue-composition-api

How can I get the data from a child component in Vue3?


Im newbie in web development, and also in vue. My idea is to make a component that has some user input, like text, a selection from a combobox and a checkbox. This component should be genereted dinamically by the user, I mean, the user needs to be able to add more and more of this components in the web via the "+" button on the parent component:

// Child component
<template>
    <div class="row">
        <p>Key:</p>
        <input type="text" v-model.trim="key">
        <p>Type:</p>
        <select name="type" v-model="type">
            <option value="Integer">Integer</option>
            <option value="String">String</option>
            <option value="List">List</option>
        </select>
        <p>Required:</p>
        <input type="checkbox" name="required" v-model="required">
        <button>More options</button>
    </div>
</template>

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

const key = ref('key');
const type = ref('Integer');
const required = ref(true);

defineExpose({
    'key':key,
    'type':type,
    'required':required
})

</script>

<style scoped>
.row {
    display: flex;
}
p{
    padding: 20px;
}
</style>
// ParentComponent
<template>
      <div>
        <div v-for="(item, index) in items" :key="index">
          <Row :is="item"/>
        </div>
        <button @click="addComponent">+</button>
        <button @click="logComponentsData"></button>
      </div>
</template>
    
<script setup>
import { ref } from 'vue';
import Row from './Row.vue';

const items = ref([]);

const addComponent = () => {
  items.value.push({});
};

</script>

I used refs and v-model and also a sort of rendering list that im not sure if it is correctly applied.

In the web I can se through the vue extension that the data is changing in my child components: website img

But I dont know how is the right or any way possible for me to log all the child components data (key, type, required) for later usage.

I may want to store that data on local storage later on.

Any help would be much appreciated!


Solution

  • Vue SFC Playground

    Use v-model for the child component:

    // ParentComponent
    <template>
    <div>{{items}}</div>
          <div>
            <div v-for="(_, index) in items" :key="index">
              <ChildComponent v-model="items[index]"/>
            </div>
            <button @click="addComponent">+</button>
          </div>
    </template>
        
    <script setup>
    import { ref } from 'vue';
    import ChildComponent from './ChildComponent.vue';
    
    const items = ref([]);
    
    const addComponent = () => {
      items.value.push({key:'key', type:'Integer', required:true});
    };
    
    </script>
    

    ChildComponent.vue

    // Child component
    <template>
        <div class="row">
            <p>Key:</p>
            <input type="text" v-model.trim="value.key">
            <p>Type:</p>
            <select name="type" v-model="value.type">
                <option value="Integer">Integer</option>
                <option value="String">String</option>
                <option value="List">List</option>
            </select>
            <p>Required:</p>
            <input type="checkbox" name="required" v-model="value.required">
            <button>More options</button>
        </div>
    </template>
    
    <script setup>
    
    import {computed} from 'vue';
    
    const props = defineProps({'modelValue':{type: Object, required:true}});
    const emit = defineEmits(['update:modelValue']);
    
    const value = computed({
      get(){ return props.modelValue; },
      set(val){ emit('update:modelValue', value.value); }
    });
    
    </script>
    
    <style scoped>
    .row {
        display: flex;
    }
    p{
        padding: 20px;
    }
    </style>