ASP.NET Core 3.1 - Message Modal

Ken Haggerty
Created 05/08/2020 - Updated 09/07/2021 04:53

This article will demonstrate the implementation of a global Bootstrap message modal. I will assume you have downloaded the FREE ASP.NET Core 3.1 - FIDO Utilities Project or created a new ASP.NET Core 3.1 Razor Pages project. See Tutorial: Get started with Razor Pages in ASP.NET Core.

FIDO Utilities Project and Article Series

The ASP.NET Core 3.1 - FIDO Utilities Project (FUP) is a collection of utilities I use in the ASP.NET Core 5.0 - Users Without Passwords Project (UWPP). I have upgraded the FUP with Bootstrap v5 and Bootstrap Native v4. FUP version 2.1 features SingleUser Authentication, Admin Page with Send Email Tests, ExceptionEmailerMiddleware, Bootstrap v5 Detection JavaScript, Copy and Paste Demo, Offcanvas Partial Demo, and Path QR Code Demo. The SMTP Settings Tester is updated and now located in the authorized Pages > Admin folder. The EmailSender and AES Cipher Demo are also updated. Registered users can download the source code for free on KenHaggerty. Com at Manage > Assets. The UWPP is published at Fido. KenHaggerty. Com.

Update 09/07/2021

I updated message-modal.js to v2.1.1.

Update 09/01/2021

Bootstrap 5 is designed to be used without jQuery, but it’s still possible to use our components with jQuery. If Bootstrap detects jQuery in the window object it’ll add all of our components in jQuery’s plugin system; this means you’ll be able to do $('[data-bs-toggle="tooltip"]'). tooltip() to enable tooltips. The same goes for our other components. See Still want to use jQuery? It’s possible!. I updated message-modal.js to support Bootstrap v5 and v4 css. The message-modal.js depends on Bootstrap v5 js, Bootstrap Native, or jQuery. I updated the article with the new version. The FUP v2.1 also features ajax-modal.js, confirm-modal.js, and field-update.js.

The FIDO processes involve interaction between the client, authenticator and user without the server. I found the frequency of JS alerts required better messaging. A message to inform the user something went wrong and they need to start over is the most important. This oops message needs to prevent the user from continuing on the current page and provide a link to the start over page. My extensive research found Oops means you made a mistake and realize it now. Opps means you made a mistake and wish to try for the bonus round.

The first oops message in the Users Without Passwords Project was a Bootstrap-jQuery modal with no dismiss button, a link to start over, a 'static' backdrop and keyboard=false. I liked it enough to develop a success message to present before automatically navigating to the goal. I liked that enough to develop a global message modal by adding the html for a modal to _Layout. cshtml and a showMessageModal() function to site.js. I liked that enough to develop message-modal.js which dynamically creates the html. Variables reference the created modal components which allow the message modal to co-exisit with other modals. It can be loaded in _Layout. cshtml for global access or used locally by loading from the page. The showMessageModal() function has defaults and parameters.

The first messages used a lot of jQuery. I converted the selectors and attribute modifications to vanilla JavaScript but the modal instance requires jQuery or Bootstrap Native. KenHaggerty.Com implements Bootstrap Native and ASP.NET Core 2.2 - BootstrapNative Client Validation. The FIDO Utilities Project implements libman.json and includes Bootstrap Native, jQuery and jQuery validation. I implemented a global UseBSN flag and added Bootstrap, Bootstrap Native and jQuery CDN links with integrity metadata in _Layout. cshtml. See more on libman.json at ASP.NET Core 2.2 - Manage Client-Side Libraries.

The message-modal.js depends on Bootstrap v5 js, Bootstrap Native, or jQuery. The dependencies are detected in the DOMContentLoaded event. The message-modal.js supports Bootstrap v5 and v4.

Bootstrap v5 js Vs Bootstrap Native Vs jQuery

Bootstrap Bundle
  • bootstrap.bundle.min.js v5.1.0 = 78,468 bytes
Bootstrap Native
  • bootstrap-native.min.js v4.0.5 = 39,893 bytes
  • pollyfill.min.js v3.0.15 = 3,554 bytes
jQuery
  • jquery.min.js v3.6.0 = 89,501 bytes
message-modal.js
'use strict'
/*!
* Copyright © Ken Haggerty (https://kenhaggerty.com)
* Licensed under the MIT License.
* Bootstrap v5 and v4 Message Modal - Version 2.1.1
* Depends on Bootstrap v5 js, Bootstrap Native, or jQuery
*/

// Defaults are var (public) for the MessageGenerator only
var defaultMessage = 'Thank you for supporting KenHaggerty.Com.';
var defaultMessageClass = 'alert-primary';
var defaultMessageAllowDismiss = true;
var defaultMessageDismissText = 'OK';
var defaultMessageDismissClass = 'btn-primary';
var defaultMessageIncludeLink = false;
var defaultMessageLinkHref = 'https://kenhaggerty.com';
var defaultMessageLinkTarget = '_self';
var defaultMessageLinkText = 'KenHaggerty.Com';
var defaultMessageLinkClass = 'btn-primary';
var defaultMessageHideBackdrop = false;

let useJQ$ = false;
let useBSN = false;
let useBV5 = false;
let modalInstance = null;

let modalBodyDiv = document.createElement('div');
modalBodyDiv.classList.add('modal-body');
modalBodyDiv.classList.add('text-center');

let messageElement = document.createElement('h4');
let messageClassDiv = document.createElement('div');
messageClassDiv.appendChild(messageElement);
modalBodyDiv.appendChild(messageClassDiv);

let messageLinkButton = document.createElement('a', { href: '/' });
modalBodyDiv.appendChild(messageLinkButton);

let messageDismissButton = document.createElement('button', { type: 'button' });
messageDismissButton.dataset.dismiss = 'modal'; // v4
messageDismissButton.dataset.bsDismiss = 'modal'; // v5
modalBodyDiv.appendChild(messageDismissButton);

let modalContentDiv = document.createElement('div');
modalContentDiv.classList.add('modal-content');
modalContentDiv.appendChild(modalBodyDiv);

let modalDialogDiv = document.createElement('div', { role: 'document' });
modalDialogDiv.classList.add('modal-dialog');
modalDialogDiv.classList.add('top-5');
modalDialogDiv.appendChild(modalContentDiv);

let modalDiv = document.createElement('div', { tabindex: '-1', role: 'dialog', ariaHidden: "true" });
modalDiv.classList.add('modal');
modalDiv.classList.add('message-modal');
modalDiv.classList.add('fade');
modalDiv.appendChild(modalDialogDiv);

document.body.appendChild(modalDiv);

function showMessageModal(
    message = defaultMessage,
    messageClass = defaultMessageClass,
    allowDismiss = defaultMessageAllowDismiss,
    dismissText = defaultMessageDismissText,
    dismissClass = defaultMessageDismissClass,
    includeLink = defaultMessageIncludeLink,
    linkHref = defaultMessageLinkHref,
    linkTarget = defaultMessageLinkTarget,
    linkText = defaultMessageLinkText,
    linkClass = defaultMessageLinkClass,
    hideBackdrop = defaultMessageHideBackdrop) {

    if (message.length === 0) message = defaultMessage;
    let messageParse = message.toString();
    if (messageParse.indexOf('DOMException') !== -1) message = messageParse.substring(14);
    if (messageParse.indexOf('NotAllowedError') !== -1) message = messageParse.substring(17);
    if (messageClass.length === 0) messageClass = defaultMessageClass;
    if (dismissText.length === 0) dismissText = defaultMessageDismissText;
    if (dismissClass.length === 0) dismissClass = defaultMessageDismissClass;
    if (linkHref.length === 0) linkHref = defaultMessageLinkHref;
    if (linkTarget.length === 0) linkTarget = defaultMessageLinkTarget;
    if (linkText.length === 0) linkText = defaultMessageLinkText;
    if (linkClass.length === 0) linkClass = defaultMessageLinkClass;

    messageElement.innerText = message;

    messageClassDiv.classList.remove(...messageClassDiv.classList);
    messageClassDiv.classList.add(messageClass);
    messageClassDiv.classList.add('px-2');
    messageClassDiv.classList.add('py-1');
    messageClassDiv.classList.add('mb-3');

    messageDismissButton.textContent = dismissText;
    messageDismissButton.classList.remove(...messageDismissButton.classList);
    messageDismissButton.classList.add('btn');
    messageDismissButton.classList.add(dismissClass);

    messageLinkButton.classList.add('d-none');

    if (includeLink) {
        messageLinkButton.setAttribute('href', linkHref);
        messageLinkButton.setAttribute('target', linkTarget);
        messageLinkButton.textContent = linkText;
        messageLinkButton.classList.remove(...messageLinkButton.classList);
        messageLinkButton.classList.add('btn');
        messageLinkButton.classList.add(linkClass);

        if (allowDismiss) {
            messageLinkButton.classList.add('mr-2', 'me-2'); // v4 & v5
        } else {
            messageDismissButton.classList.add('d-none');
            if (useBV5) {
                modalInstance = new bootstrap.Modal(modalDiv, { backdrop: 'static', keyboard: false });
                modalInstance.show();
            } else if (useBSN) {
                modalInstance = new BSN.Modal(modalDiv, { backdrop: 'static', keyboard: false });
                modalInstance.show();
            } else if (useJQ$) {
                $('.message-modal').modal('dispose');
                $('.message-modal').modal({ backdrop: 'static', keyboard: false }, 'show');
            }
            return;
        }
    }

    if (hideBackdrop) {
        if (useBV5) {
            modalInstance = new bootstrap.Modal(modalDiv, { backdrop: false, keyboard: false });
            modalInstance.show();
        } else if (useBSN) {
            modalInstance = new BSN.Modal(modalDiv, { backdrop: false, keyboard: false });
            modalInstance.show();
        } else if (useJQ$) {
            $('.message-modal').modal('dispose');
            $('.message-modal').modal({ backdrop: false, keyboard: false }, 'show');
        }
    } else {
        if (useBV5) {
            modalInstance = new bootstrap.Modal(modalDiv);
            modalInstance.show();
        } else if (useBSN) {
            modalInstance = new BSN.Modal(modalDiv);
            modalInstance.show();
        } else if (useJQ$) {
            $('.message-modal').modal('dispose');
            $('.message-modal').modal('show');
        }
    }
}

document.addEventListener('DOMContentLoaded', function () {
    if (window.jQuery) {
        if ($.fn.modal) useJQ$ = true;
        else alert('Bootstrap-jQuery modal was not found.');
    } else if (window.BSN) {
        if (window.BSN.Modal) useBSN = true;
        else alert('BootstrapNative Modal was not found.');
    } else if (window.bootstrap) {
        if (bootstrap.Modal) useBV5 = true;
        else alert('Bootstrap v5 Modal was not found.');
    } else
        alert('Bootstrap v5 js, BootstrapNative, or jQuery is required by the Bootstrap Message Modal.');
});

The project includes a Modal Message Generator which dynamically creates the minimal signature for the showMessageModal function with examples.

Message Modal Generator
Message Modal Generator Mobile
More Modal Message
More Modal Message Mobile

Comment Count = 0

Please log in to comment.

Login Register
Logged in users receive web notifications.
Web Notifications