Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Maison012's avatar

How to work with reusable modal ?

I have a modal where i can create users and a modal where i can edit users. Until now i have used hard code with vue js, it means i just write modals at the same page but the code starts to grow too much. Now i am trying to use reucable component but dont work as i except.

Modal component

<template>
    <div>
        <div class="modal fade" id="modal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                <div class="modal-header">
                    <h5 v-if="$slots.modalTitle" class="modal-title" id="exampleModalLabel">
                        <slot name="modalTitle"/>
                    </h5>
                    <button type="button" class="btn-close" data-mdb-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <slot></slot>
                </div>
                <div v-if="$slots.modalSubmitBtn" class="modal-footer">
                    <button @click.prevent="submit" type="button" data-mdb-dismiss="modal" class="btn btn-primary">
                        <slot name="modalSubmitBtn" />
                    </button>
                </div>
                </div>
            </div>
        </div>    
    </div>
</template>

<script>
    export default {

        methods: {
            submit() {
                this.$emit('submit_changers')
            }
        }
    }
</script>

Here is my page where i call modals


                    <Modal @submit_changers="addUser">
                        <template v-slot:modalTitle>
                            Add User
                        </template>
                        <form id="" class="form-horizontal validate-form">
                            <div class="form-group mb-2">                
                                <input v-model="user_id" id="user_id" type="number" class="form-control" placeholder="user_id">        
                            </div>          
                            <div class="form-group mb-2">                
                                <input v-model="name" id="name" type="text" class="form-control" placeholder="name">        
                            </div>          
                            <div class="form-group mb-2">                
                                <input v-model="email" id="email" type="email" class="form-control" placeholder="email">        
                            </div>          
                            <div class="form-group mb-2">                
                                <input v-model="password" id="password" type="password" class="form-control" placeholder="password">        
                            </div>          
                        </form>
                        <template v-slot:modalSubmitBtn>
                            Add User
                        </template>
                    </Modal>

                    <!-- Edit Modal -->
                    <Modal @submit_changers="updateUser">
                        <template v-slot:modalTitle >
                            Reusable Edit Modal
                        </template>
                        <form id="signin" class="form-horizontal validate-form">
                            <div class="form-group">                
                                <input v-model="editname" id="name" type="text" class="form-control" placeholder="Name">        
                            </div>        

                            <div class="form-group">  
                                <input v-model="editemail" id="email" type="email" class="form-control" placeholder="Email">
                            </div> 

                            <div class="form-group">  
                                <input v-model="password" id="email" type="password" class="form-control" placeholder="Password">
                            </div>
                            
                            <select v-model="editrole" class="form-select">
                                <option v-for="role in roles" :value="role.id">{{role.title}}</option>
                            </select>
                        </form>
                        <template v-slot:modalSubmitBtn >
                            Edit User
                        </template>
                    </Modal>

<button type="button" class="btn btn-success" data-mdb-toggle="modal" data-mdb-target="#modal">
                                Add User
  </button>

// button for edit modal
<button type="button" class="btn  btn-sm btn-secondary"  data-mdb-toggle="modal" data-mdb-target="#modal" @click="editUser(user.id)">Edit</button>

every time i press each buttons i get only first modal. What am i doing wrong

0 likes
22 replies
MohamedTammam's avatar

Create two boolean variable for each model.

Your component would like

<script setup>
const showCreateModel = ref(false);
const showEditModel = ref(false);
</script>
<template>
	<!-- Create Modal -->
	<Modal @submit_changers="addUser" v-model="showCreateModel">
	<!-- ... -->
	</Modal>

	<!-- Edit Modal -->
	<Modal @submit_changers="updateUser" v-model="showEditModel">
    <!-- ... -->
	</Modal>

		<button type="button" class="btn btn-success" @click="showCreateModel = true">
			Add User
		</button>

		
		<button type="button" class="btn  btn-sm btn-secondary"  @click="editUser(user.id); showEditModel = true">Edit</button>

</template>

https://mdbootstrap.com/docs/vue/components/modal/

Maison012's avatar

@MohamedTammam I am using optional api and tryed this but it does not work. Now i cant open modals.

 data(){
            return {
                showEditModel: false,
                showCreateModel: false,

i have copied your ecample buttons also v-model

MohamedTammam's avatar

Sorry, in your modal component you need to add the following

<div v-if="modelValue">
        <div class="modal fade" id="modal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                <div class="modal-header">
                    <h5 v-if="$slots.modalTitle" class="modal-title" id="exampleModalLabel">
                        <slot name="modalTitle"/>
                    </h5>
                    <button type="button" class="btn-close" data-mdb-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <slot></slot>
                </div>
                <div v-if="$slots.modalSubmitBtn" class="modal-footer">
                    <button @click.prevent="submit" type="button" data-mdb-dismiss="modal" class="btn btn-primary">
                        <slot name="modalSubmitBtn" />
                    </button>
                </div>
                </div>
            </div>
        </div>    
    </div>
props: ['modelValue'],
emits: ['update:modelValue'],
methods: {
	closeModal() {
		this.$emit('update:modelValue', false);
	}
}
Maison012's avatar

@MohamedTammam There is no error. But still does not work. I think closeModal() is function to close my modal. But first problem : Modals does not open first.

MohamedTammam's avatar

@Leon012 In your component model add this :class selctor

<div class="modal fade" id="modal" :class="{show: modelValue}" ...

Sorry, I didn't use bootstrap like that for a while.

Maison012's avatar

@MohamedTammam I dont have a repo but this is the modal component

<template>
    <div v-if="modelValue">
        <div class="modal fade" id="modal" :class="{show: modelValue}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                <div class="modal-header">
                    <h5 v-if="$slots.modalTitle" class="modal-title" id="exampleModalLabel">
                        <slot name="modalTitle"/>
                    </h5>
                    <button type="button" class="btn-close" data-mdb-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <slot></slot>
                </div>
                <div v-if="$slots.modalSubmitBtn" class="modal-footer">
                    <button @click.prevent="submit" type="button" data-mdb-dismiss="modal" class="btn btn-primary">
                        <slot name="modalSubmitBtn" />
                    </button>
                </div>
                </div>
            </div>
        </div>    
    </div>
</template>

<script>
    export default {

        props: ['modelValue'],
        emits: ['update:modelValue'],

        methods: {
            submit() {
                this.$emit('submit_changers')
            },

            closeModal() {
                this.$emit('update:modelValue', false);
            }
        }
    }
</script>

also i tryed to change <Modal @submit_changers="updateUser" v-if="showEditModel"> on the page when i call modal but it does not work. Modal does not open

MohamedTammam's avatar

@Leon012 Oh, here's Vue2 version

<template>
    <div v-if="value">
        <div class="modal fade" id="modal" :class="{show: value}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
           <!-- ... -->
        </div>    
    </div>
</template>

<script>
    export default {
        props: ['value'],
        methods: {
            submit() {
                this.$emit('submit_changers')
            },
            closeModal() {
                this.$emit('input', false);
            }
        }
    }
</script>
Maison012's avatar

@MohamedTammam not work again

modal cmponent
<template>
    <div v-if="value">
        <div class="modal fade" id="modal" :class="{show: value}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">            <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 v-if="$slots.modalTitle" class="modal-title" id="exampleModalLabel">
                        <slot name="modalTitle"/>
                    </h5>
                    <button type="button" class="btn-close" data-mdb-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <slot></slot>
                </div>
                <div v-if="$slots.modalSubmitBtn" class="modal-footer">
                    <button @click.prevent="submit" type="button" data-mdb-dismiss="modal" class="btn btn-primary">
                        <slot name="modalSubmitBtn" />
                    </button>
                </div>
                </div>
            </div>
        </div>    
    </div>
</template>

<script>
    export default {
        props: ['value'],
        methods: {
            submit() {
                this.$emit('submit_changers')
            },
            closeModal() {
                this.$emit('input', false);
            }
        }
    }
</script>

maybe the problem is here

                                <button type="button" class="btn  btn-sm btn-secondary"  @click="editUser(user.id); showEditModel = true">Edit</button>

<!-- Edit Modal -->
                    <Modal @submit_changers="updateUser" v-model="showEditModel">
                        <template v-slot:modalTitle >
                            Reusable Edit Modal
                        </template>
                        <form id="signin" class="form-horizontal validate-form">
                            <div class="form-group">                
                                <input v-model="editname" id="name" type="text" class="form-control" placeholder="Name">        
                            </div>        

                            <div class="form-group">  
                                <input v-model="editemail" id="email" type="email" class="form-control" placeholder="Email">
                            </div> 

                            <div class="form-group">  
                                <input v-model="password" id="email" type="password" class="form-control" placeholder="Password">
                            </div>
                            
                            <select v-model="editrole" class="form-select">
                                <option v-for="role in roles" :value="role.id">{{role.title}}</option>
                            </select>
                        </form>
                        <template v-slot:modalSubmitBtn >
                            Edit User
                        </template>
                    </Modal>

data(){
            return {
                showEditModel: false,
Maison012's avatar

@Elliot_putt I have upgraded to vue 3.0 but now i have some other problems with my component registration i think

ERROR in ./resources/js/components/workers/WorkersComponent.vue       
Module build failed (from ./node_modules/vue-loader/lib/index.js):    
TypeError: Cannot read properties of undefined (reading 'parseComponent')

component registration

/**
 * First we will load all of this project's JavaScript dependencies which
 * includes Vue and other libraries. It is a great starting point when
 * building robust, powerful web applications using Vue and Laravel.
 */

require('./bootstrap');
import Vue from 'vue';
import VueProgressBar from 'vue-progressbar'

window.Vue = require('vue').default;

/**
 * The following block of code may be used to automatically register your
 * Vue components. It will recursively scan this directory for the Vue
 * components and automatically register them with their "basename".
 *
 * Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
 */

// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
const VueProgressBarOptions = {
    color: '#695CFE',
    failedColor: '#87111d',
    thickness: '5px',
    transition: {
        speed: '0.2s',
        opacity: '0.6s',
        termination: 300
    },
    autoRevert: true,
    location: 'top',
    inverse: false
};
Vue.use(VueProgressBar, VueProgressBarOptions);

Vue.component('workers', require('./components/workers/WorkersComponent.vue').default);



/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */

const app = new Vue({
    el: '#app',
});

Maison012's avatar

@MohamedTammam Anyway, I was thinking to migrate on newest version also for other features. But now i see a problem with my registration component

Please or to participate in this conversation.