laravelvuejs3inertiajsbulma

Modal controls in vue components


I'm making an edit user account page in Laravel, Vue, and Inertia. The user changes their information via forms that are stored as reusable modals.

The demo button makes the modal work fine, but when I try to put the open/close functionality in a component different to the modal component itself, it doesn't register. Not sure what I'm doing wrong.

UpdateInfo.vue

<script setup>

import Card_Header from "../../../Components/Card_Header.vue";
import Modal from "../../../Components/Modal.vue";
import { router, useForm } from "@inertiajs/vue3";

</script>

<template>
    <Head title=" || Update Info" />

        <div class="card">
            <div class="card-content">
                
                <Card_Header title="Your Details" /><!-- open/close button here -->     

                        <Modal>
                          <!-- modal content -->
                        </Modal>

            </div><!-- card-content -->
        </div><!-- card -->
</template>

CardHeader.vue

<script setup>

defineProps({
title: String,
}); 
    
</script>

<template>

    <nav class="level is-mobile">
        <div class="level-left">
            <div class="level-item">
                <h3 class="subtitle is-size-4">{{ title }}</h3>
            </div><!-- level-item -->
        </div><!-- Left side -->
        <div class="level-right">
            <div class="level-item">
                <button class="button" @click="openModal = !openModal">Edit</button><!-- where open/close button needs to be -->
            </div><!-- level-item -->
        </div><!-- Right side -->
    </nav>

</template>

Modal.vue

<script setup>

import { onMounted, ref } from "vue";

const props = defineProps({})

const openModal = ref(false)

</script>

<template>
<button class="button" @click="openModal = !openModal">Demo button, delete later</button>
    <div class="modal" :class="{ 'is-active': openModal }">
        <div class="modal-background"></div>
            <div class="modal-content">
                <div class="card">
                    <div class="card-content">
                
                        <slot />

                    </div>
                </div>

            </div><!-- modal content -->
        <button class="modal-close is-large" aria-label="close" role="button" @click="openModal = !openModal"></button>
    </div><!-- modal -->

</template>

Solution

  • openModal is only defined in Modal.vue, it does not exist anywhere else. If openModal should be used in both Card_Header.vue and Modal.vue then it would probably be best to define it in their common parent, UpdateInfo.vue, then two-way bind openModal to the child components using v-model. Here is what I mean (showing only relevant code):

    import Card_Header from "../../../Components/Card_Header.vue";
    import Modal from "../../../Components/Modal.vue";
    
    const openModal = ref(false)
    
    <template>
      <Card_Header v-model="openModal" />
      <Modal v-model="openModal" />
    </template>
    

    Card_Header.vue

    const openModal = defineModel()
    ...
    <button class="button" @click="openModal = !openModal">Edit</button>
    

    Modal.vue

    const openModal = defineModel()
    ...
    <button class="modal-close is-large" aria-label="close" role="button" @click="openModal = !openModal"></button>
    

    Vue Playground demo