vue.jsvue-material

Opening (and Closing) vue material dialog on different components


I'm trying to open a vue material dialog on a child component. I want the trigger button to remain on the parent and the dialog box template on a child component so that it would be easier to maintain.

The dialog box opens correctly, but when I click on the close button, the dialog box closes, but I'm unable to open it again with the trigger button. I'm using a prop to pass variables from the parent to the child.

How do I close the dialog box and be able to open it up again?

app.vue:

<template>
  <div>
    <button @click="showContextMenu = true">
      <span>Show Context Menu</span>
    </button>
    <contextMenu :showContextMenu="showContextMenu"></contextMenu>
  </div>
</template>

<script>
import contextMenu from "contextMenu.vue";

export default {
  data() {
    return {
      showContextMenu: false,
    };
  },
  components: {
    contextMenu,
  },
};
</script>

contextMenu.vue:

<template>
  <md-dialog :md-active.sync="showContextMenu">
    <md-dialog-title>Preferences</md-dialog-title>Dialog
    <md-dialog-actions>
      <md-button class="md-primary" @click="showContextMenu = false">Close</md-button>
    </md-dialog-actions>
  </md-dialog>
</template>

<script>
export default {
  data() {
    return {};
  },
  props: ["showContextMenu"],
};
</script>

Solution

  • Passing props to child components creates a one way binding, thus you cannot use them to pass state from child to its parent. You can have you contextMenu emit an event, on which you change the value of the showContextMenu variable in parent. Remember the following: props are used for passing state from parent to child components and events for doing the reverse.

    The code would look like this:

    app.vue:

    <template>
      <div>
        <button @click="showContextMenu = true">
          <span>Show Context Menu</span>
        </button>
        <contextMenu :showContextMenu="showContextMenu" @close="showContextMenu = false"></contextMenu>
      </div>
    </template>
    
    <script>
    import contextMenu from "contextMenu.vue";
    
    export default {
      data() {
        return {
          showContextMenu: false,
        };
      },
      components: {
        contextMenu,
      },
    };
    </script>
    

    contextMenu.vue:

    <template>
      <md-dialog :md-active.sync="showContextMenu">
        <md-dialog-title>Preferences</md-dialog-title>Dialog
        <md-dialog-actions>
          <md-button class="md-primary" @click="$emit('close')">Close</md-button>
        </md-dialog-actions>
      </md-dialog>
    </template>
    
    <script>
    export default {
      data() {
        return {};
      },
      props: ["showContextMenu"],
    };
    </script>