John
John

Reputation: 1297

Vuejs modal component passing data

I am stuck making a modal component for my app in VueJS. I want to be able to put it in its own component for reusability, be able to pass custom content and have multiple modals.

I made the component and it looks like this from the VueJS docs:

Modal.vue

<template>
  <div ref="modal">
    <script type="text/x-template" id="modal">
      <transition name="modal">
        <div class="modal-mask">
          <div class="modal-wrapper">
            <div class="modal-container">

              <div class="modal-header">
                <slot name="header">
                  Header
                </slot>
              </div>

              <div class="modal-body">
                <slot name="body">
                  Body
                </slot>
              </div>

              <div class="modal-footer">
                <slot name="footer">
                  Footer
                </slot>
                <button class="btn btn-primary" @click="$emit('close')">
                  Button
                </button>
              </div>
            </div>
          </div>
        </div>
      </transition>
    </script>
  </div>
</template>


<script>

  export default {
    components: { },
    props: ['header', 'footer', 'body', 'button'],
    data: () => ({
      showModal: false
    }),
    methods: {
      open () {
        console.log('Opening modal')
        this.showModal = true
      }
    }
  }
</script>

<style>

  #modal {
    /*color: #000;*/
  }

  .modal-mask {
    position: fixed;
    z-index: 9998;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, .5);
    display: table;
    transition: opacity .3s ease;
  }

  .modal-wrapper {
    display: table-cell;
    vertical-align: middle;
  }

  .modal-container {
    width: 300px;
    margin: 0px auto;
    /*padding: 20px 30px;*/
    background-color: #25262D;
    color: #FEFEFE;
    border-radius: 3px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, .33);
    transition: all .3s ease;
    font-size: 1.2em;
  }

  .modal-header {
    border-radius: 3px;
    background-color: #202128;
    border: none;
  }

  .modal-header h3 {
    margin-top: 0;
    color: #42b983;
  }

  .modal-body {
    margin: 20px 0;
    /*background-color: #202128;*/
    border: none;
  }

  .modal-footer {
    text-align: center;
    border: none;
  }

  .modal-footer .btn {
    font-size: 1.0em;
  }

  /*
   * The following styles are auto-applied to elements with
   * transition="modal" when their visibility is toggled
   * by Vue.js.
   *
   * You can easily play with the modal transition by editing
   * these styles.
   */

  .modal-enter {
    opacity: 0;
  }

  .modal-leave-active {
    opacity: 0;
  }

  .modal-enter .modal-container,
  .modal-leave-active .modal-container {
    -webkit-transform: scale(1.1);
    transform: scale(1.1);
  }

</style>

I add a modal in my App.vue:

<button @click="openUpdatedModal()" type="button" class="btn btn-default" data-toggle="modal" data-target="#modal">
          Launch Updated Modal
      </button>

      <modal ref="updatedModal" v-if="showModal" @close="showModal = false">
        <!--
          you can use custom content here to overwrite
          default content
        -->
        <div slot="header">custom header</div>
      </modal>

<script>

import Modal from './components/Modal'

export default {
    components: { Modal },
    data: () => ({
        showModal: false
    }),
    methods: {
        openUpdatedModal () {
            this.$refs.updatedModal.open()
        }
    }
}
</script>

When I click the button I get the text in console "Opening modal" but nothing happens.

I can summon it and it works if I have ALL the code in App.vue

What am I missing?

Upvotes: 1

Views: 1896

Answers (1)

Martin K
Martin K

Reputation: 364

I made it work by creating a ModalComponent.vue and removing the script tag as Phil suggested in the comments. Here's the code.

ModalComponent.vue:

<template>
 <transition name="modal">
    <div class="modal-mask">
    <div class="modal-wrapper">
        <div class="modal-container">

        <div class="modal-header">
            <slot name="header">
            default header
            </slot>
        </div>

        <div class="modal-body">
            <slot name="body">
            default body
            </slot>
        </div>

        <div class="modal-footer">
            <slot name="footer">
            default footer
            <button class="modal-default-button" @click="$emit('close')">
                OK
            </button>
            </slot>
        </div>
        </div>
    </div>
    </div>
 </transition>
</template>
<script>
  export default{

  }
</script>

Here's how I defined my component:

Vue.component('modal', ModalComponent);

Modal button in markup:

<button id="show-modal" @click="showModal = true">Show Modal</button>

And the modal component being called on the page:

    <modal v-if="showModal" @close="showModal = false">
        <!--
        you can use custom content here to overwrite
        default content
        -->
        <h3 slot="header">custom header</h3>
    </modal>

It's worth noting that I had to declare the showModal property wherever I use my modal.

Upvotes: 1

Related Questions