Topic: Call modals from other components
                  
                  jay2jam
                  pro
                  asked 6 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 6 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 6 years ago
                    
Hi there again,
This article can be very helfpful for You: https://mdbootstrap.com/articles/vue/vuex-or-emit-basics-of-communication-between-vue-components/
Best!
                      
                      Mikołaj Smoleński
                      staff
                        answered 6 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 6 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">•</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 6 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 6 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 6 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 6 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 6 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 6 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 6 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 6 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 6 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.
FREE CONSULTATION
Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.
Answered
- 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