[Vuejs]-Passing props to VueJS component thru v-repeat turns up empty

0👍

In edit.vue declare the v-for (instead of v-repeat) and pass the props. In workout.vue, declare the props so they are available in the template.

edit.vue:

<template>
    <workout
        v-for="workout in workouts" :id="workout.id" :name="workout.name"  :key="workout.id"
    ></workout>
</template>

<script>
    export default {
        props: ['workouts']
    }
</script>

workout.vue:

<template>
    <div>{{ id }} :: {{ name }}</div>
</template>

<script>
    export default {
        props: ['id', 'name']
    }
</script>

Demo:

Vue.component('edit-plans', {
    template: "#edit-plans-tpl",
  props: ['workouts']
});
Vue.component('workout', {
  template: "#workout-tpl",
  props: ['id', 'name']
});

new Vue({
  el: '#app',
  data: {
    message: [1,2]
  }
})
<script src="https://unpkg.com/vue@latest/dist/vue.min.js"></script>

<template id="edit-plans-tpl">
<div>
    <workout
        v-for="workout in workouts" :id="workout.id" :name="workout.name" :key="workout.id"
    ></workout>
</div>
</template>
<template id="workout-tpl">
    <div>{{ id }} :: {{ name }}</div>
</template>

<div id="app">
  <edit-plans :workouts='[{"id":1,"name":"1st Plan"}, {"id":2,"name":"2nd Plan"}]'>
    
  </edit-plans>
</div>

Update, per comment: What if I just want to pass each full workout into the child instead of each part of the object? In other words, I’d be able to do {{ workout.id }} :: {{ workout.name }}

You can use v-bind for that. Just change the edit.vue, keep workout.vue the same as above.

edit.vue:

<template>
    <workout
        v-for="workout in workouts" v-bind="workout" :key="workout.id"
    ></workout>
</template>

<script>
    export default {
        props: ['workouts']
    }
</script>

workout.vue: same as above.

Demo for this:

Vue.component('edit-plans', {
    template: "#edit-plans-tpl",
  props: ['workouts']
});
Vue.component('workout', {
  template: "#workout-tpl",
  props: ['id', 'name']
});

new Vue({
  el: '#app',
  data: {
    message: [1,2]
  }
})
<script src="https://unpkg.com/vue@latest/dist/vue.min.js"></script>

<template id="edit-plans-tpl">
<div>
    <workout
        v-for="workout in workouts" v-bind="workout" :id="workout.id"
    ></workout>
</div>
</template>
<template id="workout-tpl">
    <div>{{ id }} :: {{ name }}</div>
</template>

<div id="app">
  <edit-plans :workouts='[{"id":1,"name":"1st Plan"}, {"id":2,"name":"2nd Plan"}]'>
    
  </edit-plans>
</div>

Update, per comment: So no matter what, I have to declare every property within the workout object? I can’t just do props: ['workout'] within the workout.vue so I can do {{ workout.id }} :: {{ workout.name }}?

You can declare the workout prop in the child and pass it in the parent like :workout="workout":

edit.vue:

<template>
    <workout
        v-for="workout in workouts" :workout="workout" :key="workout.id"
    ></workout>
</template>

<script>
    export default {
        props: ['workouts']
    }
</script>

workout.vue:

<template>
    <div>{{ workout.id }} :: {{ workout.name }}</div>
</template>

<script>
    export default {
        props: ['workout']
    }
</script>

Demo for this:

Vue.component('edit-plans', {
    template: "#edit-plans-tpl",
  props: ['workouts']
});
Vue.component('workout', {
  template: "#workout-tpl",
  props: ['workout']
});

new Vue({
  el: '#app',
  data: {
    message: [1,2]
  }
})
<script src="https://unpkg.com/vue@latest/dist/vue.min.js"></script>

<template id="edit-plans-tpl">
<div>
    <workout
        v-for="workout in workouts" :workout="workout" :key="workout.id"
    ></workout>
</div>
</template>
<template id="workout-tpl">
    <div>{{ workout.id }} :: {{ workout.name }}</div>
</template>

<div id="app">
  <edit-plans :workouts='[{"id":1,"name":"1st Plan"}, {"id":2,"name":"2nd Plan"}]'>
    
  </edit-plans>
</div>

Note: :key="workout.id" added to the loop: This default mode is efficient, but only suitable when your list render output does not rely on child component state or temporary DOM state. (thanks @channasmcs).

Leave a comment