Holiday Notice: Support will be provided on a limited scale from December 24th, 2024, to January 2nd, 2025. Happy holidays and a wonderful New Year!


Topic: Call modals from other components

jay2jam pro asked 5 years ago


Hello,

i am creating several components, also i created 1 Modals.vue, which shoud includes all modals, sure :-)

Now i import this component into App.vue and call them.

From component Content.vue, i want to call a modal, i am using a MDB standard Modal. Normally it should work like that, also i get no errors, so compiling is fine. But nothing happens, when i click on mdb-button.

Do i have to miss anything?

Rgds


Mikołaj Smoleński staff answered 5 years ago


Hello Stefan,

So everything is fine ;) No we can move to the second part of Your project - emiting close event. You'll need to make a method for all close events, like this:

    <mdb-modal  side position="top-right" v-if="showModal5" @close="closeModal">
            <mdb-modal-header class="divider-outside-bottom">
                <mdb-modal-title><img src="../assets/ecommerce-icon.png" class="img-fluid modalIcons"> <span class="modalTitle">Unsere eCommerce Angebote</span></mdb-modal-title>
            </mdb-modal-header>
            <mdb-modal-body>
                <div class="container">

                    Hier kommt der Text rein

                </div>
            </mdb-modal-body>
            <mdb-modal-footer>
                <mdb-btn flat size="lg" darkWaves  @click.native="closeModal"><img class="img-fluid modalBackIcon" src="../assets/arrow-right.png"/></mdb-btn>
            </mdb-modal-footer>
        </mdb-modal>



     import { mdbModal, mdbModalHeader, mdbModalTitle, mdbModalBody, mdbModalFooter, 
    mdbBtn, mdbInput, mdbTextarea, mdbIcon } from 'mdbvue';
    export default {
    name: 'Overlays',
    components: {
      mdbModal,
  mdbModalHeader,
  mdbModalTitle,
  mdbModalBody,
  mdbModalFooter,
  mdbBtn,
  mdbInput,
  mdbTextarea,
  mdbIcon
},
props: {
  show: {
    type: Boolean,
    default: false
  }
},
data() {
  return {
    showModal5: this.show
  }
},
methods: {
   closeModal() {
       this.showModal5 = false;
       this.$emit('closeModal');
   }
},
watch: {
  show(newVal) {
    this.showModal5 = newVal;
  }
}

And then in Your App.vue You have to get the closeModal event:

    <template>
        <div>
            <Overlays :show="show" @closeModal="closeModal" />
            <button @click="openModal">Open</button>
        </div>
    </template>   

(...)
     import Overlays from '@/components/Overlays.vue';

         export default {
           name: 'App',
          components: {
          Overlays
         },
         data() {
            return {
             show: false
           }
          },
          methods: {
           openModal() { 
                this.show= true
           },
            closeModal() {
                this.show= false
           }
          }
         }

Mikołaj Smoleński staff answered 5 years ago


Mikołaj Smoleński staff answered 5 years ago


Hi there again,

As the warning says - You should avoid mutating prop. You just need to update closeModal method in Modal Component to this:

methods: {
  closeModal() {
    this.impressum = false;
    this.$emit('closeModal');
  }
},

Best regards


jay2jam pro answered 5 years ago


Sorry Mikolaj, i have to ask you again. This is working but i get a warning:

    [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever 
     the parent component re-renders. Instead, use a data or computed property based on the 
    prop's value. Prop being mutated: "show"

 found in

 ---> <ModalImpressum> at src/modals/site/ModalImpressum.vue
   <Footer> at src/components/Footer.vue
     <App> at src/App.vue
       <Root>

Part of Modal template:

<mdb-modal  side position="top-right" v-if="impressum" @closeModal="closeModal">
 <mdb-modal-header v-sticky>
<mdb-modal-title> <span class="modalTitle">Impressum</span></mdb-modal-title>
<mdb-btn flat size="xs" darkWaves  @click="closeModal" class="modalHeaderButton"><img 
class="img-fluid modalBackIcon" src="../../assets/arrow-right-gray.png"/></mdb-btn>
 </mdb-modal-header>
  <mdb-modal-body>

Modal Component:

import { mdbModal, mdbModalHeader, mdbModalTitle, mdbModalBody, mdbModalFooter, 
mdbBtn, mdbInput, mdbTextarea, mdbIcon, mdbCol, mdbRow,Sticky } from 'mdbvue';
export default {
name: 'ModalImpressum',
components: {
  mdbModal,
  mdbModalHeader,
  mdbModalTitle,
  mdbModalBody,
  mdbModalFooter,
  mdbBtn,
  mdbInput,
  mdbTextarea,
  mdbIcon,
  mdbCol,
  mdbRow
},
props: {
  show: {
    type: Boolean,
    default: false
  }
},
data() {
  return {
    impressum: this.show
  }
},
directives:{
  'sticky': Sticky
},
methods: {
  closeModal() {
    this.show = false;
    this.$emit('closeModal');
  }
},
watch: {
  show(newVal) {
    this.impressum = newVal;
  }
}
  }

Call from Footer:

 <ModalImpressum :show="show" @closeModal="closeModal" />
 <mdb-btn @click="openModal" flat class="hi-icon hi-icon-archive text- 
 muted">Impressum</mdb-btn> <span class="ibull">&bull;</span>


  export default {
    name: 'Footer',
    components: {
      mdbModal, mdbModalHeader, mdbModalTitle, mdbModalBody, mdbModalFooter, 
     mdbBtn, mdbInput, mdbTextarea, mdbIcon,    mdbCard,
     mdbCardBody, mdbContainer, mdbRow, mdbCol, mdbTooltip, mdbJumbotron, 
    ModalImpressum
},
data() {
  return {
    show: false
  }
},
directives:{
  'sticky': Sticky
},
methods: {
  openModal() {
    this.show= true
  },
  closeModal() {
    this.show= false
  }
  }
   }

Thx again


jay2jam pro answered 5 years ago


Yes this did the trick thx for it :-)


jay2jam pro answered 5 years ago


Hello Mikolaj,

thank you so much, but it doesn't work :-/ Now i can open the modal and close, but i can't reopen again.

I get no errors.

Rgds Stefan


Mikołaj Smoleński staff answered 5 years ago


In Your App.vue it should be:

    <template>
        <div>
            <Overlays :show="show"/>
            <button @click="openModal">Open</button>
        </div>
    </template>   

(...)
     import Overlays from '@/components/Overlays.vue';

         export default {
           name: 'App',
          components: {
          Overlays
         },
         data() {
            return {
             show: false
           }
          },
          methods: {
           openModal() { this.show= true
           }
           }
           }

Rgds


jay2jam pro answered 5 years ago


Same problem :-/

Overlay:

 <mdb-modal  side position="top-right" v-if="showModal5" @close="showModal5 = false">
        <mdb-modal-header class="divider-outside-bottom">
            <mdb-modal-title><img src="../assets/ecommerce-icon.png" class="img-fluid modalIcons"> <span class="modalTitle">Unsere eCommerce Angebote</span></mdb-modal-title>
        </mdb-modal-header>
        <mdb-modal-body>
            <div class="container">

                Hier kommt der Text rein

            </div>
        </mdb-modal-body>
        <mdb-modal-footer>
            <mdb-btn flat size="lg" darkWaves  @click.native="showModal5 = false"><img class="img-fluid modalBackIcon" src="../assets/arrow-right.png"/></mdb-btn>
        </mdb-modal-footer>
    </mdb-modal>



 import { mdbModal, mdbModalHeader, mdbModalTitle, mdbModalBody, mdbModalFooter, 
mdbBtn, mdbInput, mdbTextarea, mdbIcon } from 'mdbvue';
export default {
name: 'Overlays',
components: {
  mdbModal,
  mdbModalHeader,
  mdbModalTitle,
  mdbModalBody,
  mdbModalFooter,
  mdbBtn,
  mdbInput,
  mdbTextarea,
  mdbIcon
},
props: {
  show: {
    type: Boolean,
    default: false
  }
},
data() {
  return {
    showModal5: this.show
  }
},
watch: {
  show(newVal) {
    this.showModal5 = newVal;
  }
}

}

App.vue:

Open Modal

import Overlays from '@/components/Overlays.vue';

 export default {
   name: 'App',
  components: {
  Overlays
 },
 data() {
    return {
     showModal5: false
   }
  },
  methods: {
   openModal() { showModal5 = true
   }
   }
   }

Rgds Stefan


Mikołaj Smoleński staff answered 5 years ago


You need also to define showModal in Your App.vue like this:

   data() {
     return {
       showModal: false
     }
   }

Best regards


Mikołaj Smoleński staff answered 5 years ago


Hi Stefan,

It's almost correct ;) The easiest way will be like this:

<Overlays :show="showModal" />
<button @click="openModal">Open Modal</button>

methods: {
 openModal() { this.showModal = true
}

In Overlay.vue:

   props: {
    show: {
      type: Boolean,
      default: false
     }
    },
   data() {
     return {
       showModal5: this.show
     }
    },
    watch: {
      show(newVal) {
        this.showModal5 = newVal;
      }
    }

It should work now.

Best regards


jay2jam pro commented 5 years ago

Hello Mikolaj, thx for your help :-) Now i get this message in App.vue:

[Vue warn]: Error in v-on handler: "ReferenceError: showModal is not defined"

I also changed showModal to showModal5, but the same message

What can i do now?

Rgds Stefan


jay2jam pro answered 5 years ago


Hello Mikolaj,

i did this in App.vue(parent):

<Overlays :show="true" />
<button @click="openModal">Open Modal</button>
 methods: {
openModal() { this.$refs.showModal5.show()
}

In Overlay.vue i did this:

  data() {
  return {
    showModal5: false
  }
},
watch: {
  show(newVal) {
    this.showModal5 = newVal;
  }
}

I get this warning:

[Vue warn]: Error in v-on handler: "TypeError: Cannot read property 'show' of undefined"

Sorry, but i am new to vue and mdb vue

Rgds and thx for helping me Stefan


Mikołaj Smoleński staff answered 5 years ago


Hello,

You have to pass the main modal state to the appropriate component. In most cases it can be done by passing it as a prop. For example:

<Modal :show="true" ...></Modal>

The prop value should be triggered by a function, e.x. after button click.

Then You will have to watch for the prop changes inside Your own component. For example:

watch: {
   show(newVal) {
      this.showModal = newVal;
   }
}

And then inside Modal.vue the mdb-modal should appeal to the showModal value, e.x.:

<mdb-modal v-if="showModal " ... >

Best regards


Mikołaj Smoleński staff commented 5 years ago

Also, if You want to access Modal from another component (not App.vue) at first You will need to $emit the 'show' value from Content.vue file.



Please insert min. 20 characters.

FREE CONSULTATION

Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.

Status

Answered

Specification of the issue

  • ForumUser: Pro
  • Premium support: No
  • Technology: MDB Vue
  • MDB Version: 4.8.1
  • Device: MAC
  • Browser: CHROME
  • OS: Moave
  • Provided sample code: No
  • Provided link: No
Tags