[Vuejs]-How render component in v-for by button from parent

0👍

You can take advantage of an item… index available in v-for directive (e.g. v-for="(item, i) in items"), to bind it (index of the item) to the function which shows an item by changing it’s property:

Update: Initial answer has been deleted after requirements refinement.

Since you prefer to keep from mutation of items, you can wrap them in Map object (as keys) and keep visibility settings separately as Map values. Unfortunately, as far as I know, for the time being Vue.js does not support reactivity for Map objects, that’s why I have to trigger rerendering manually by using forceUpdate:

Vue.config.devtools = false;
Vue.config.productionTip = false;
Vue.component('child', {
  template: '<p>Visible child</p>'
})

new Vue({
  el: "#demo",
  template: `
<div>
  <div v-for="item in items">
    <button @click="toggleChild(item)">Toggle child</button>
    <div>{{item.name}}</div>
    <child v-if="isVisible(item)" :item="item"></child>
  </div>
</div>
`,
  data () {
    return {
      itemsMap: new Map(
        [
          { name: 'test1' },
          { name: 'test2' }
        ].map(item => [item, { visible: false }])
      )
    };
  },
  methods: {
    toggleChild(item) {
      this.itemsMap.set(item, { visible: !this.itemsMap.get(item).visible });
      this.$forceUpdate();
    },
    isVisible(item) {
      return this.itemsMap.get(item).visible;
    }
  },
  computed: {
    items: function() {
      return Array.from(this.itemsMap.keys());
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo"></div>

0👍

You have to store info about state of every item (if it was clicked) in your data. Then, when you click on button you should update clicked property for particular item. Finally if item.clicked is set on true you will show your child component (or any other html).

<template>
  <div>
    <div v-for="item in items" :key="item.id">
      <button @click="item.clicked = true" >Show child</button>
      {{item.name}}
      <div v-if="item.clicked">Item child</div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data: function() {
    return {
      items: [
        {
          id: 1,
          name: 'test1',
          clicked: false
        },
        {
          id: 2,
          name: 'test2',
          clicked: false
        },
        {
          id: 3,
          name: 'test3',
          clicked: false
        }
      ]
    }
  }
}
</script>

0👍

Plain and simple you just have to set some flag for latter v-if:

<div id="app">
  <div v-for="item in items">
    <button @click="$set(item, 'shown', true)">Show child</button>
    <div>{{ item.name }}</div>
    <div v-if="item.shown">Child component</div>
  </div>
</div>

Here, $set() is used because initial item could lack shown field, so setting it directly with item.shown=true won’t be reactive.

You can also hide button after click:

<button @click="$set(item, 'shown', true)" v-if="!item.shown">Show child</button>

To toggle visibility you just have to do it like this:

<button @click="$set(item, 'shown', !item.shown)">
  {{ item.shown ? 'Hide' : 'Show' }} child
</button>

JSFiddle

Leave a comment