Tips for managing modal closure when the InertiaJS form succeeds?

Hello everyone! Currently, I'm involved in a Laravel project where I am using laravel/breeze VueJS with Inertia. The login functionality is implemented using a bootstrap modal component. While validation and authentication are working smoothly, the only issue I'm facing is that after successful authentication, the modal closes but the backdrop remains visible.

I've noticed that the form onSuccess does not trigger any emit function. Interestingly, when I used console.log, it worked perfectly fine.

Below you can find the code snippets for reference...

Header.vue

<script setup>
import { ref } from 'vue';
import Modal from '@/Components/Modal.vue'

let thisModal = ref(null)

function showModal() {
    thisModal.value.show()
}

function closeModal() {
    thisModal.value.close()
}
</script>

<template>
    <header class="shadow-sm">
        <Modal v-if="! $page.props.auth.user" ref="thisModal">
            <template #body>
                <Login @closeParent="closeModal" @showParent="showModal" />
                <Register />
            </template>
        </Modal>
    </header>
</template>

Modal.vue

<script setup>
import { onMounted, ref } from 'vue'
import { Modal } from 'bootstrap'

defineProps({
    title: String
})

let modalEle = ref(null)
let thisModalObj = null

onMounted(() => {
    thisModalObj = new Modal(modalEle.value)
})

function _show() {
    thisModalObj.show()
}

function _close() {
    thisModalObj.hide()
}

defineExpose({ show: _show, close: _close })
</script>

<template>
    <div class="modal fade" tabindex="-1" role="dialog" ref="modalEle">
        <div class="modal-dialog modal-dialog-centered" role="document">
            <div class="modal-content">
                <div class="modal-header bg-secondary">
                    <slot name="header" />
                </div>
                <div class="modal-body tab-content py-4">
                    <slot name="body" />
                </div>
                <slot name="footer" />
            </div>
        </div>
    </div>
</template>

Login.vue (Form location)

<script setup>
import { Link, useForm } from '@inertiajs/vue3'
import Checkbox from '@/Components/Checkbox.vue'
import InputError from '@/Components/InputError.vue'
import InputLabel from '@/Components/InputLabel.vue'
import PrimaryButton from '@/Components/PrimaryButton.vue'
import TextInput from '@/Components/TextInput.vue'
import PasswordToggle from '@/Components/PasswordToggle.vue'

defineProps({
    canResetPassword: {
        type: Boolean,
    },
    status: {
        type: String,
    },
})

const form = useForm({
    email: '',
    password: '',
    remember: false,
})

const emit = defineEmits()

const submit = () => {
    form.post(route('login'), {
        onFinish: () => form.reset('password'),
        // onBefore hides the modal
        onBefore: () => emit('closeParent'),
        // onError shows the modal
        onError: () => emit('showParent'),
        // Use onSuccess instead
        onSuccess: () => emit('closeParent') 
    })
}
</script>

<template>
    <form @submit.prevent="submit" id="login-tab" class="tab-pane fade show active" autocomplete="off" novalidate>
        <!-- Form fields here -->
    </form>
</template>

The above code works such that the modal is hidden upon clicking the Sign in button and will reappear if there is an error like validation failure or incorrect credentials. However, I want it to close only when authentication is successful. The problem may lie in the fact that the onSuccess method receives an Inertia response as shown in the controller below:

AuthenticatedSessionController.php

/**
 * Handle an incoming authentication request.
 */
 public function store(LoginRequest $request) // : RedirectResponse
 {
     $request->authenticate();

     $request->session()->regenerate();

     return redirect()->intended(RouteServiceProvider::HOME);
  }

Also, I'd like to mention that the modal code was shared by @OJay in response to a query posted here.

Answer №1

After extensive testing, I still haven't found the most effective way to address this issue. Instead of using an API, I have opted to stick with Inertia response/redirects. To fix the problem of the modal backdrop persisting after a successful login redirect, I have chosen to manually remove the modal backdrop on the modal parent update event.

  1. If the login is successful, a redirect response is triggered.

    return redirect()->intended(RouteServiceProvider::HOME);

This results in the page being redirected to the home page without properly closing the modal form, causing the modal backdrop to cover the entire page.

  1. To address this issue, I have implemented code that checks the body tag for modal classes and scans the entire document for

    <div class="modal-backdrop fade show"></div>
    , along with a body style attribute of
    style="margin-bottom: 8px; overflow: hidden; padding-right: 0px;"

  2. When the modal is opened, Bootstrap updates the body tag class to

    <body class="handheld-toolbar-enabled modal-open">
    along with the style attribute changing to
    style="margin-bottom: 8px; overflow: hidden; padding-right: 0px"
    . It then adds a new element
    <div class="modal-backdrop fade show"></div>

  3. Taking note of these changes, I have devised a solution to remove and update these elements, which is activated by the modal parent's onUpdated event. The code is outlined below

<script setup>
import { ref, onUpdated } from 'vue'
// Get the document's body tag
const body = ref(document.body)

// Function to check and update body tag
const checkAndModifyBody = () => {
    const modalOpenClass = 'modal-open'
    const expectedStyle = 'margin-bottom: 8px;'
    const modalBackdropSelector = 'div.modal-backdrop.fade.show'

    if (body.value.classList.contains(modalOpenClass)) {
        body.value.classList.remove(modalOpenClass)
    }

    if (body.value.style.cssText !== expectedStyle) {
        body.value.style.cssText = 'margin-bottom: 8px;'
    }

    const modalBackdrop = body.value.querySelector(modalBackdropSelector)
    if (modalBackdrop) {
        modalBackdrop.remove()
    }
}

// Watch for changes and run the checkAndModifyBody function
watch(body, () => {
    checkAndModifyBody()
});

// Initial check
onUpdated(() => {
    checkAndModifyBody()
})

This method may not be the most elegant vue approach to solving the issue.

Thank you all for your input, and if anyone has a more efficient solution, please share it with me.

Cheers!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Manipulating arrays in a JSON file with JavaScript

Struggling with adding a new value to an array stored in a file.json? The array currently contains ["number1", "number2"], and you want to add "number3". However, attempts to define a variable in the JavaScript file containi ...

Using node.js to send a response with response.writeHead on the http module

While working on my own custom http module, I stumbled upon a few confusing points while studying the official node.js http module api: When a user utilizes the response.writeHead(statusCode, [reasonPhrase], [headers]) function, are the headers suppose ...

Display a preview image at the conclusion of a YouTube video

I am currently working on an iOS device and have a Youtube video thumbnail that, when clicked, disappears and the video automatically plays in fullscreen mode using an iframe. It's working perfectly. Now, I would like to know how I can make the thumb ...

Using angular.js variables in the script tag: A step-by-step guide

Currently, I am working on a project that involves displaying elements on a view using Angular.js and attempting to connect these DOM elements using jQuery connections. While the elements are being displayed correctly, I am encountering an issue when tryin ...

Having trouble sorting data-text values that include colspan cells

Latest Update: Encountered an issue with incorrect sorting and frozen sortings when dealing with a cell containing the colspan attribute. Refer to https://jsfiddle.net/2zhjsn31/12/ where the problem arises for the date 2018-06-24 On https://jsfiddle.n ...

Retrieve the file for saving using the HttpPost method in Asp.Net MVC

In my Asp.Net MVC project, there is a page where users can edit data loaded into a table, such as changing images, strings, and the order of items. Once all edits have been made, the client clicks on a Download button to save the resulting xml-file on the ...

Embed a website in an iframe and modify a portion of the URL within the embedded page

Welcome to my first question here! I am looking for a solution that will allow me to load a webpage inside an iframe while modifying parts of the URLs in any links on the page with different text. For example, let's say we load a website like "myweb ...

Highcharts: generating numerous series utilizing JSON dataset

I am struggling to generate a chart with multiple series using JSON data. Although I have successfully created one with a single series, it doesn't look right and the legend is missing. I need guidance on how to rectify this issue. Currently, I only h ...

Enhance the interactivity of Javascript results by making them clickable

I'm new to JavaScript and facing a challenge. I have a JSON file that I'm using to retrieve data. I now want to make the search results clickable so they can be directly inserted into an input field. Eventually, I plan on incorporating them into ...

What are some of the methods that can be used with the Facebook API to interact with the Like button

I am working on developing a JavaScript script that will automatically click on all the LIKE buttons for posts loaded on Facebook in the Chrome browser. Input: "" Or any other FB page,Groups,Profiles Step1: I will scroll down to load all the posts S ...

Setting up a Node.js http2 server along with an http server specifically designed for a single

In my upcoming project, I am interested in implementing the http2 protocol. My goal is to have both http and http2 servers running on a single domain and port, if feasible. When a client that does not support http2 connects, communication will default to ...

Can a file be transferred from an Electron application to an Express server by supplying the file path?

This is my current objective: A user drags and drops a file into Electron Electron uses a python script via child_process.exec to convert the file The conversion process generates a new file in the same directory as the original With knowledge of the path ...

Send information as FormData object

I'm getting the data in this format: pert_submit: {systemId: "53183", pert-id: "176061", score: 0, q2c: "3\0", q2t: "", …} Now I need to send it as FormData in my post request. Since I can't use an ...

Checking for an empty value with javascript: A step-by-step guide

Below is an HTML code snippet for checking for empty or null values in a text field: function myFormValidation() { alert("Hello"); var name = document.getElementById("name").value; alert(name); if (name == null || name == "") { document.ge ...

What is the best way to modify directives in response to updates in services?

In my directive (parent-directive), I have a slider called mySlider. When the slider is stopped, it triggers an event that calls an Angular $resource service with two parameters. The service then returns an object. The structure of the directives is as fo ...

What techniques can I use to generate a 3D visual effect by shifting the background image layer as the user scrolls (creating a Parallax effect

I have combined two images in the heading; one on top of the other. My goal is to create a subtle vertical movement in the background image as the user scrolls, giving the illusion of depth. Both images share the same width, but the background image is tal ...

Numerous Kendo windows are layered on top of each other, yet the text divisions within them remain distinct

I am currently working on a project that involves laying out multiple Kendo windows in rows. Specifically, I need to display 4 windows in each row and have them shift left when closed. My framework of choice is Bootstrap 3. Everything works as expected w ...

Single-select components in React Native

I am currently working on implementing a simple single selectable item feature, illustrated in the image provided below. https://i.stack.imgur.com/U2rJd.png At this moment, I have set up an array containing my data items and utilized the .map function to ...

Syncing states between backend and frontend: A step-by-step guide using vuex and vue-router

Currently, I am working on a single-page-application utilizing vue-cli3 and npm. The issue at hand entails populating an integer value (referred to as counter) stored in a vuex state. This value is supposed to be incremented/decremented from the backend t ...

Ensure that all checkboxes are only selected within a single table

I have a challenge with selecting all check boxes in multiple tables when the header check box is selected. I am attempting to achieve this using jQuery without needing to parse or pass in the table id. Currently, when I select one header check box, all th ...