2

hey my code looks like this:

componentData: [
   { name: TestPane, props: { data: this.cars }, id: 1 },
   { name: TestPane, props: { data: this.persons }, id: 2 },
]
<div v-for="component in componentData" :key="component.id">
   <component v-bind:is="component.name" v-bind="component.props">
   </component>
</div>

the props are not reactive. When I pass the props normally without the loop with :data=cars they are reactive. But I need to pass them in a loop for my project. Any Ideas?

Kevin W.
  • 101
  • 1
  • 8
  • 1
    you just wrote `v-bind` that is same like doing `:="component.props"` it makes no sense. you need to write what you want to pass like `v-bind:data` – bill.gates Nov 13 '20 at 14:06
  • 1
    Assuming `componentData` is defined in the same `data` block as `cars` and `persons`, that's the problem. They won't exist at the time you define `componentData`, even if they are listed above. (The `v-bind` syntax [is valid](https://vuejs.org/v2/api/#v-bind) though.) – Dan Nov 13 '20 at 14:09
  • Can you add to your `TestPane` this: `created(){console.log(this.data);}` ? – webprogrammer Nov 13 '20 at 14:18
  • If @Dan is right, you can check this answer https://stackoverflow.com/questions/49614837/how-to-reference-data-variable-from-another-data-variable-in-vue-2 – webprogrammer Nov 13 '20 at 14:20
  • Ifaruki v-bind is valid, like the documentation Dan linked says. @Dan yes you are right. Is there a solution for my problem? – Kevin W. Nov 13 '20 at 14:21
  • @webprogrammer no I can't. It is undefined like Dan said. Only if I use the :data syntax it works – Kevin W. Nov 13 '20 at 14:23
  • @KevinW. "not reactive" was a pretty misleading phrase. Next time always show error message. – webprogrammer Nov 13 '20 at 14:25
  • Posted a working demo for you using a computed – Dan Nov 13 '20 at 14:42

1 Answers1

1

It would work unless you've defined your data like this:

data() {
  return {
    cars: [ ... ],
    persons: [ ... ],
    componentData: [
      { name: TestPane, props: { data: this.cars }, id: 1 },
      { name: TestPane, props: { data: this.persons }, id: 2 },
    ]
  }
}

this.cars and this.persons aren't accessible when you define componentData. Use a computed to maintain reactivity:

new Vue({
  el: "#app",
  data() {
    return {
      cars: [ ... ],
      persons: [ ... ]
    }
  },
  computed: {
    componentData() {
      return [
        { name: TestPane, props: { data: this.cars }, id: 1 },
        { name: TestPane, props: { data: this.persons }, id: 2 },
      ]
    }
  }
});

EDIT: Here's a demo

const TestPane = {
  template: `
    <div class="pane">
      {{ data }}
    </div>
  `,
  props: ['data']
}

/***** APP *****/
new Vue({
  el: "#app",
  data() {
    return {
      cars: ['honda', 'ferrari'],
      persons: ['Bob', 'Mary']
    }
  },
  computed: {
    componentData() {
        return [
        { name: TestPane, props: { data: this.cars }, id: 1 },
        { name: TestPane, props: { data: this.persons }, id: 2 },
      ]
    }
  }
});
.pane {
  padding: 12px;
  background: #dddddd;
  margin: 4px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div v-for="component in componentData" :key="component.id">
     <component v-bind:is="component.name" v-bind="component.props">
     </component>
  </div>
</div>
Dan
  • 59,490
  • 13
  • 101
  • 110
  • Hey I tried all your solutions while you was editing :D Your solution is working, except in the initial load. I get multiple undefined messages there, but after that it works fine. How can I initiate the computed data with null, so that I can do a v-if? – Kevin W. Nov 13 '20 at 14:48
  • 1
    Ha, changed my mind after the first version wasn't reactive. If you're loading the data async, you could either wrap the `v-for` with a `v-if` until it arrives (preferable), or you could do something like `data: this.cars || []` and `data: this.persons || []` in the computed. – Dan Nov 13 '20 at 14:52
  • i load the data via api calls in the mounted hook. So yeah I want to use v-if on the whole component array. But how? In your 'before-editing' solution I could used "v-if="componentData" because it was null initially. – Kevin W. Nov 13 '20 at 14:56
  • 1
    That's usually done with a `v-if="isLoaded"` data property you create, which starts as `false` and you set to `true` when the async operation completes – Dan Nov 13 '20 at 14:57