Conditionally prevent Bootstrap 4 modal closing on "esc" - javascript

I'm using session storage to show and hide a modal when loading the page for the first time. I don't know how to use cookies so I just use session storage.
In the modal, I change the header and the close button when you close it for the first time, then is accessible as a "help modal" instead of "getting started".
I want to prevent to close the modal with esc if the session storage is not set up and is in "getting started" mode, but when you close the modal and you reopen it as a "help modal" enable the esc event.
At the moment I make it work at 50%, first time you can't use esc but if you open it as a "help" you still can't use esc, although, if you reload the page esc it works,
Here is the else part of my code, effective when the session storage is not setup:
} else {
// show the help modal
$('#help').modal({
keyboard: false
});
$('#help').modal('show');
$('#help').on('hidden.bs.modal', function (e) {
keyboard: true
})
}
The documentation (https://getbootstrap.com/docs/4.0/components/modal/#events)
said that the .on('hidden.bs.modal' event is fired when the modal has finished being hidden from the user.
Which event I have to use to make it works as I want?

As it seems, you cannot simply re-configure an already initialized modal by supplying new options object to it. Meaning that if you do the following:
$('#help').modal({
keyboard: false
});
$('#help').modal({
keyboard: true
});
…than the latter statement won't have any effect.
So, in order to overcome this, I would suggest to destroy the first modal –the one with keyboard: false– and create a new modal that listens to keyboard events too.
Check the working snippet below.
Note: the first modal is created at pageload from code using keyboard: false, while consecutive modals launched by the button are set with the defaults, so with keyboard: true.
// } else {
// show the help modal
$('#help').modal({
keyboard: false
});
// Note the `one` binding
$('#help').one('hidden.bs.modal', function (event) {
$('#help').modal('dispose');
});
// }
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#help">
Open Help
</button>
<div id="help" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">HELP</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>This is the Help modal</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js"></script>

Related

Bootstrap modal on form submit not displaying at correct point

Requirement
I want to display a fixed message to the user whilst a file is being uploaded and attached to an email to discourage clicking back or refreshing the page or repeatedly clicking the submit button.
Background
I'm using bootstrap v3.3.7 and JQuery v3.3.1.
I thought a good way to tackle this requirement was to make use of the Bootstrap Modal plugin, especially when I realised you could fix the modal on screen using:
$("#modal-foo").modal({backdrop: 'static',keyboard: false});
I have the following modal:
#model Web.ViewModels.Site.Foo.FooViewModel
<div class="modal fade" id="modal-foo" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true" style="display: none;">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h4 class="modal-title" id="modal-label">
<i class="fa fa-spin fa-spinner"></i> Uploading your file and submitting it for review
</h4>
</div>
<!-- Modal Body -->
<div class="modal-body">
<p>We're currently uploading and submitting your file for review.</p>
<p>This may take a few moments. Please do not hit the back button or try to refresh this page whilst this is happening.</p>
</div>
</div>
</div>
</div>
I have the following form:
<form id="fooform" asp-action="fooaction" asp-controller="foocontroller" asp-route-fooid="#Model.FooId" method="post" enctype="multipart/form-data" class="form-horizontal">
I have the following button:
<input type="submit" value="Submit" class="btn btn-primary" />
And the following jquery:
//when dom loaded hooks
$.when($.ready).then(function () {
$('#fooform').on('submit', function () {
if ($(this).valid()) {
//we've passed the unobtrusive validation so now present the message to the user
$("#modal-foo").modal({
backdrop: 'static',
keyboard: false
});
}
});
})
Issue
What I was hoping would happen is that the modal would appear once the unobtrusive validation has passed, and is displayed until the user is redirected to a thank you page.
What I'm finding happen is that the modal isn't appearing until later in the process.
For example, if I put some alerts in to see what's happening, using the code below, the modal doesn't appear until after 'here3'. It's as though the .modal is firing an instruction to browser to display the modal but it doesn't action it immediately.
//when dom loaded hooks
$.when($.ready).then(function () {
$('#fooform').on('submit', function () {
alert('here1');
if ($(this).valid()) {
//we've passed the unobtrusive validation so now present the message to the user
alert('here2');
$("#modal-foo").modal({
backdrop: 'static',
keyboard: false
});
alert('here3');
}
});
})
Alternative attempt to achieve requirement
I've tried using an anchor instead of a submit button but again, the modal doesn't appear until after 'here3':
<a class="btn btn-primary" onclick="showModal();">Submit</a>
Javascript function:
function showModal() {
if ($('#fooform').valid()) {
//we've passed the unobtrusive validation so now present the message to the user
alert('here1');
$("#modal-foo").modal({
backdrop: 'static',
keyboard: false
});
alert('here2');
//can I somehow wrap the submit in a promise or delegate so that after the modal appears it does the submit?
$('#fooform').submit();
alert('here3');
}
}
Question
How can I achieve my requirement? As per my comment in the Javascript function above, can I wrap the form submit in a promise or delegate or can I set something on the DOM to fire after the modal has displayed or is there an alternative to the Modal that I should look at?
The problem is while you click the submit button your page reloading
that's why you cannot see your modal
$.when($.ready).then(function () {
$('#fooform').on('submit', function (e) {
e.preventDefault();//added here
// if ($(this).valid()) {
//we've passed the unobtrusive validation so now present the message to the user
$("#modal-foo").modal({
backdrop: 'static',
keyboard: false
});
// }
});
})
see your above code i used 'e.preventDefault()' to block your submission on click
Now you can see your model
But your 'valid()' command will not work here, because form is prevented from
submitting, that's why i commented out that....
So change your code according to this.....
One method is using AJAX you can send data without page reload...
otherwise give a button to open model and put submit button on the model...
There is one more chance that model will not work...
while inserting scripts it must be in order that jquery must insert before other plugins,
insert,
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
above code first,
then try,
i am including the working full code below
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.validation/1.16.0/jquery.validate.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.validation/1.16.0/additional-methods.min.js"></script>
</head>
<body>
#model Web.ViewModels.Site.Foo.FooViewModel
<div class="modal fade" id="modal-foo" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true" style="display: none;">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h4 class="modal-title" id="modal-label">
<i class="fa fa-spin fa-spinner"></i> Uploading your file and submitting it for review
</h4>
</div>
<!-- Modal Body -->
<div class="modal-body">
<p>We're currently uploading and submitting your file for review.</p>
<p>This may take a few moments. Please do not hit the back button or try to refresh this page whilst this is happening.</p>
</div>
</div>
</div>
</div>
<form id="fooform" asp-action="fooaction" asp-controller="foocontroller" asp-route-fooid="#Model.FooId" method="post" enctype="multipart/form-data" class="form-horizontal">
</form>
<a class="btn btn-primary" onclick="showModal();">Submit</a>
</body>
<script>
function showModal() {
if ($('#fooform').valid()) {
//we've passed the unobtrusive validation so now present the message to the user
alert('here1');
$("#modal-foo").modal({
backdrop: 'static',
keyboard: false
});
alert('here2');
//can I somehow wrap the submit in a promise or delegate so that after the modal appears it does the submit?
// $('#fooform').submit();
alert('here3');
}
}
</script>
</html>
In the end I got this working by using the following. Hopefully, someone else may find this useful:
Same button and form
<input type="submit" value="Submit" class="btn btn-primary" />
<form id="fooform" asp-action="fooaction" asp-controller="foocontroller" asp-route-fooid="#Model.FooId" method="post" enctype="multipart/form-data" class="form-horizontal">
Modal
Note the additional data-backdrop and data-keyboard attributes on the 1st div
#model Web.ViewModels.Site.Foo.FooViewModel
<div data-backdrop="static" data-keyboard="false" class="modal fade" id="modal-foo" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true" style="display: none;">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h4 class="modal-title" id="modal-label">
<i class="fa fa-spin fa-spinner"></i> Uploading your file and submitting it for review
</h4>
</div>
<!-- Modal Body -->
<div class="modal-body">
<p>We're currently uploading and submitting your file for review.</p>
<p>This may take a few moments. Please do not hit the back button or try to refresh this page whilst this is happening.</p>
</div>
</div>
</div>
</div>
jQuery
I ended up taking the key elements from the modal plugin in the Bootstrap js file and the modal appeared at the point I expected it to whilst still giving me the modal display effects that I was looking for.
function showModal() {
var $body = $("body");
$body.addClass("modal-open");
$(document.createElement('div'))
.addClass('modal-backdrop fade in')
.appendTo($body)
var $modal = $("#modal-foo");
$modal.show();
$modal.scrollTop(0);
$modal[0].offsetWidth;
$modal.addClass('in');
}
//when dom loaded hooks
$.when($.ready).then(function () {
$('#fooform').on('submit', function () {
if ($(this).valid()) {
showModal();
}
});
})

bootstrap modal event controlling

I am trying to create a form with two 'pages' using bootstrap modal,
when the user clicks "next" it suppose to hide the modal, load new content and show it again.
but when I close the modal with .modal("hide"), it doesn't close the modal but also shows another modal and make the screen even darker.
also when I click the close button that bootstrap gives us, it shows two modals and a second later hides them, and the second time i click to open the modal i have 3 modals!
whenever i click any button in the modal it adds another modal to the page.
what can i do??
here is some code, the simplest functions that still cause that problem.
function additionFormValidate() {
if ($('#form-modal').is(':visible')) {
secondPage();
} else {
console.log("modal didnt open");
}
}
function secondPage() {
$("#form-modal").modal("hide");
}
HTML
<div class="modal fade" id="form-modal" onclick="openModal()" tabindex="-1" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content"></div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" onclick="additionFormValidate()">Next</button>
</div>
</div>
</div>
does anyone familiar with this?
sometimes you need setTimeout() to prevent javascript to working too fast.
demo: http://jsbin.com/remevolemi/3/edit?html,output
$('.btn1').click(function(){
$('#modal1').find('.modal-body').text('first content');
$('#modal1').modal('show');
});
$('.btn-next').click(function(){
$("#modal1").modal('hide'); //hide modal
setTimeout(function(){
$("#modal1").find('.modal-body').text('second content'); //change modal content
$('#modal1').modal('show');//show modal again
}, 500); //wait 0.5 sec
});
here some example for another case: http://jsbin.com/edit?html,output

jQuery Modal only Opened once after clicked

i've some problem that make make head feels so heavy... i've searched for the answer in this forum, but the problem still not solve.
my problem is i've a button that link to modals. when first time after the page refreshed the modal open while the button clicked. but not for the second time.
i've check the log and the log said
TypeError: $(...).modal is not a function[Learn More].
if i refreshed the page, it will only work once, and the second click of the button, the modals not open again...
this is my button HTML view code..
<button class="btn btn-info btn-sm btn-labeled" type="button" id="tambahUser" data-toggle = "modal" value="<?= Url::to(['/module/create'],true)?>">
this is my modal
<div id="modalSignUpSm" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-info">
<button type="button" class="close" data-dismiss="modal" id="tutupModal">
<span aria-hidden="true">×</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">Colored Header Modal</h4>
</div>
<div class="modal-body">
<div id="modalContent"></div>
</div>
</div>
</div>
</div>
and this is my js code that responsible for handling click event of the button
$('#tambahUser').click(function(event){
$('#modalSignUpSm').modal({
backdrop: 'static',
keyboard: false,
})
.modal('show')
.find('#modalContent')
.load($(this).attr('value'));
});
$('#tutupModal').click(function(){
$('#modalSignUpSm').modal('close');
});
this is my controller (i'm using Yii2) of Module/create
public function actionCreate()
{
$model = new Module();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(Url::to(['/paneladm/pengaturan/module',true]));
} else {
return $this->renderAjax('create', [
'model' => $model,
]);
}
}
My Question is why the modals only open once and after that, the button stuck..? how to resolve that...
Note: - i'm new on jQuery, and i will very thanks for every answer.
- i've search on this forum and try to resolve with create a button and every this button clicked will be firing the .modal('close') but still not work
You should either use Bootstraps data-attributes to trigger the modal on and off, or use trigger via javascript manually. Right now you are trying to do both. See this example.
So I would remove the bootstrap data-attributes and then make sure your bootstrap script is loaded before your own javascript.

Multiple Bootstrap modals in a single page

In a page, there are around 150 submenus (expandable). Every click on a submenu opens a modal with specific information for the submenu. Data is fetched initially when the page loads. I wonder what is a better way to implement the modals.
Should I write 150 modals in the same page, or write one modal then create the content dynamically?
For the latter option I need an example.
Technologies used: Bootstrap, HTML, CSS, jQuery.
You might like this example i have created, Let me know if you dont understand any where.
$(document).ready(function(e) {
// Initializing our modal.
$('#myModal').modal({
backdrop: 'static',
keyboard: false,
show: false,
});
$(document).on("click", ".modalButton", function() {
var ClickedButton = $(this).data("name");
// You can make an ajax call here if you want.
// Get the data and append it to a modal body.
$(".modal-body").html("<p>" + ClickedButton + "</p> <p>Some text in the modal.</p> ");
$('#myModal').modal('show');
});
});
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Modal Example</h2>
<!-- Trigger the modal with a button -->
<button type="button" class="btn btn-info btn-lg modalButton" data-name="Clicked Modal 1" data-toggle="modal">Open Modal 1</button>
<!-- Trigger the modal with a button -->
<button type="button" class="btn btn-info btn-lg modalButton" data-name="Clicked Modal 2" data-toggle="modal">Open Modal 2</button>
<!-- Trigger the modal with a button -->
<button type="button" class="btn btn-info btn-lg modalButton" data-name="Clicked Modal 3" data-toggle="modal" >Open Modal 3</button>
<!-- Trigger the modal with a button -->
<button type="button" class="btn btn-info btn-lg modalButton" data-name="Clicked Modal 4" data-toggle="modal">Open Modal 4</button>
<!-- Trigger the modal with a button -->
<button type="button" class="btn btn-info btn-lg modalButton" data-name="Clicked Modal 5" data-toggle="modal">Open Modal 5</button>
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal Header</h4>
</div>
<div class="modal-body">
<p>Some text in the modal.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
You can just create a single modal.
and as you have mentioned you will have 150 menu so you can give them a common class name and using a jquery get the click event of those button/menu.
You can have some ajax call to get some dynamic data if you want.
append your response to the modal body and just show the modal. Thats it!!
You can write one modal in your page. Then, every time you click a submenu, call an asynchronous function to get the appropriate data, append them to the modal and show it:
jQuery
$(document).on('click', '.submenu', function() {
$.ajax({
url: 'path/to/file',
method: 'POST',
data: { ... },
success: function(data) {
// Get the data and fill the modal
// Show modal
$('#myModal').modal('show');
},
error: function() {
// Error handling
}
});
});
Of course you should write one modal and generate content on demand. If you will go with the first option then every time you will need to make a change in the common area you will have to change +150 files! That's very bad approach.
You need to remember that web application should be consistent. This way you will save yourself a lot of time and effort.
Also, how do you plan to pull it off. Load 150 modal windows at once and than wait for data ?:P
The way I see it - create one modal that will be a framework and then fill it with data, maybe add stuff if you need it in other template file for specific case.
Cheers!
Load the data dynamically using jQuery. I'm assuming you have buttons to open each modal?
http://jsfiddle.net/h3WDq/
$('#myModal1').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
// Extract info from data-* attributes
// If necessary, you could initiate an AJAX request here (and then do the updating in a callback).
// Update the modal's content. I'm using use jQuery here, you could use it to load your data
var modal = $(this)
modal.append("<p>Test</p>");
})

Meteor's Iron Router doesn't close modal dialog

I'm using Meteor and Iron Router, and I have a modal dialog that won't hide the backdrop when it gets dismissed. To be more accurate, I want that after clicking the dismiss button, the iron router will redirect to another page. The redirection code does work, but the backdrop stays visible. If I remove the routing line - the modal is dismissed and so does the backdrop.
Here is the modal's markup:
<div class="modal fade" id="confirm-modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title" id="modal-title">Are you sure?</h4>
</div>
<div class="modal-body">
This cannot be undone.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" id="confirm-yes-button">Yes</button>
<button type="button" class="btn btn-default" data-dismiss="modal">No</button>
</div>
</div>
</div>
</div>
Here is the button that toggles the modal dialog:
<button type="button" id="delete-recipe-btn" data-target="#confirm-modal" data-toggle="modal" class="btn btn-primary btn-danger pull-right">Delete</button>
Here is the click event on the 'yes' button of the confirm modal dialog:
'click #confirm-yes-button': function() {
Recipes.remove(this._id);
$('#confirm-modal').modal('hide');
Router.go('/');
}
Why would the routing leave the backdrop visible?
There are multiple solutions to this, depending on exactly how you desire the behavior. If you want the modal to hide first, then change the page, you can use a callback on the modal's behavior.
'click #confirm-yes-button': function() {
Recipes.remove(this._id);
$('#confirm-modal')
.on('hidden.bs.modal', function() {
Router.go('/');
})
.modal('hide');
}
As to your question of why the backdrop is visible - its complicated. The backdrop is only hidden once the "hide" animation completes, and changing the page interrupts/stops this behavior.
One of the solution would be to use jQuery methods to remove backdrop
once the user has been redirected.
Accounts.onLogin(function(){
Router.go('/');
$('.modal-backdrop').remove();
});
However to use this method you need have access to Accounts.login method which can be acquired by adding
gwendall:auth-client-callbacks
package to your meteor project

Categories

Resources