Craig Ward
Craig Ward

Reputation: 2485

Sending one time event to child components

Im struggling to implement something which I think is pretty easy.

In my Vue app I loop through a list. Each list item is a child component. Each list item has an expand/collapse button. That works fine, but I want to be able to close all open items from the parent and I don't seem to be able to get that working as I would like.

The expand/collapse is controlled via a variable called isOpen so

<div v-if="isOpen">Something here</div>

I have tried using a computed property instead of the isOpen and passing props but that issue is I think it needs to act more like an event.

Consider three open list items. If the list items are controlled by a prop, and setting it to false closes the items, when an item is reopened, the prop is still false so therefore will not work a second time. I know I could change it back on the parent, but it seems wrong.

Whats the best way to accomplish this?

Upvotes: 1

Views: 999

Answers (1)

Roy J
Roy J

Reputation: 43881

If you passed an "allClosed" prop, you would need to have your child components emit events to reset it every time they opened. That seems hacky to me. I think you are right that it should be more of a parent-to-children event, which calls for an event bus.

new Vue({
  el: '#app',
  data: {
    closeBus: new Vue(),
    kids: [1, 2, 3]
  },
  components: {
    expandableThing: {
      data() {
        return {
          isOpen: true
        }
      },
      props: ['bus'],
      methods: {
        toggle() {
          this.isOpen = !this.isOpen;
        }
      },
      created() {
        this.bus.$on('close', () => this.isOpen = false);
      }
    }
  }
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
  <expandable-thing v-for="kid in kids" inline-template :bus="closeBus">
    <div>
      <div v-show="isOpen">My stuff!</div>
      <button @click="toggle">Toggle</button>
    </div>
  </expandable-thing>
  <button @click="closeBus.$emit('close')">Close all</button>
</div>

Upvotes: 1

Related Questions