Jim E Russel
Jim E Russel

Reputation: 495

Vue - v-model inside a component within a component

I'm trying to separate my project now into components to make the code readable when adjusting into a responsive app. The problem is passing the v-model from base-select -> child -> parent. How do I store the data selected to the Parent.vue items: ''? Here is my code below.

Parent.vue

<template>
  <child></child>
</template>

<script>
import Child from './components/Child'

export default {
  components: { 
    Child,
  },
  data: ()=> ({
    item: ''
  })
}
</script>

Child.vue

<template>
  // Random HTML
  // Random HTML 2
  <base-select 
  :items="select"
  >
</template>

<script>
import BaseSelect from '@/components/BaseSelect'

export default {
  components: { 
    BaseSelect,
  },
  data: ()=> ({
    select: ['Select 1', 'Select 2']
  })
}
</script>

BaseSelect.vue

<template>
  <v-select
    v-bind="$attrs"
    v-on="$listeners"
    class="body-2"
    solo
    dense
    clearable
  />
</template>

Upvotes: 1

Views: 1265

Answers (2)

dreyhiflden
dreyhiflden

Reputation: 304

You need to use $emit (documentation) to passing data back to parent components. Or you can start using Vuex (state manager for Vue.js).

You also can check the live demo here.

Upvotes: 1

Ivan Kahl
Ivan Kahl

Reputation: 618

To implement v-model you need to add a value property to each child component. Each component will also need to emit an input event so that the parent component can pick up the change (read more here). Note that if you are passing data down through too many components, you should probably look at using Vuex however in this case it would probably still be fine.

Your components would have to look something like this to pass v-model all the way to the base component:

Parent.vue

<template>
  <!-- Pass the data item below -->
  <child v-model="item"></child>
</template>

<script>
import Child from './components/Child'

export default {
  components: { 
    Child,
  },
  data: ()=> ({
    item: ''
  })
}
</script>

Child.vue

<template>
  // Random HTML
  // Random HTML 2
  <base-select 
    :items="select"
    value="value"
    @input="e => $emit('input', e)"
  >
</template>

<script>
import BaseSelect from '@/components/BaseSelect'

export default {
  components: { 
    BaseSelect,
  },
  // We add the value prop below to work with v-model
  props: {
    value: String
  },
  data: ()=> ({
    select: ['Select 1', 'Select 2']
  }),
}
</script>

BaseSelect.vue

<template>
  <v-select
    v-bind="$attrs"
    v-on="$listeners"
    value="value"
    @input="e => $emit('input', e)"
    class="body-2"
    solo
    dense
    clearable
  />
</template>

<script>
export default {
  props: {
    value: String
  }
}
</script>

You can find a similar working example that I did here.

Upvotes: 1

Related Questions