1

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?

3
  • 1
    Why do you have <script type="text/x-template" id="modal"> in your template? You're already in a template Commented Jun 20, 2017 at 4:46
  • I think @Phil is right. That can causing your issues. Template is template. Script is script. Separate them. Commented Jun 20, 2017 at 6:26
  • I used this: vuejs.org/v2/examples/modal.html removing that however still have this problem: Cannot read property 'open' of undefined at VueComponent.openUpdatedModal Commented Jun 20, 2017 at 8:28

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.