Bootstrap 3 modal problem with data piling up - javascript

Having serious data problem.
I have a button, script action, bootstrap modal confirm.
Problem
Clicking delete and agreement on modal, works like a charm. One click, one network tab/delete action. But, clicking on "delete>cancel", "delete>cancel" etc. adds as many network tab/delete actions (check img)
NB! Problem is not the 404, but that there are two (or more) actions taken, even though cancel should remove previous info/data. There is no arrays, no modal leftovers, but once you click agreement OK, as many network actions/posts are made as many you cancelled previously. And weird part is that if you click other delete, it adds THAT as well, and therefor there will be multiple deletions. It's like adding elements to delete.
Code example here: https://jsfiddle.net/cvyw6758/4/
$(document).ready(function(){
$("#action_modal").on('show.bs.modal', function (event) {
let button_ = $(event.relatedTarget),
modal_ = $(this);
let id_ = (button_.data("row") ? button_.data("row") : ""),
question_ = (button_.data("modal_body") ? button_.data("modal_body") : ""),
title_ = (button_.data("modal_title") ? button_.data("modal_title") : "Agreement"),
action_ = (button_.data("action") ? button_.data("action") : false),
url_ = (button_.data("href") ? button_.data("href") : (button_.attr("href") ? button_.attr("href") : false));
modal_.find(".modal-title").html(title_);
// do confirm action
switch (action_) {
case "approve_remove":
const elem_ = button_.parent().parent();
modal_.find(".modal-body").html(`${question_}`);
$("#confirmed").on("click", function(e) {
e.preventDefault();
// do delete
$(this).off();
$.post(`${url_}${id_}`, function(data_) {
if(data_.status == "success") {
elem_.hide();
elem_.parent().next().html(`<td colspan="3">${data_.message}</td>`);
setTimeout(function() {
elem_.parent().parent().prev().slideUp("200").remove("");
elem_.parent().parent().slideUp("200").remove("");
}, 5000);
}
else {
$(`<tr><td colspan="3">${data_.message}</td></tr>`).insertBefore(elem_.parent());
setTimeout(function() {
elem_.parent().parent().prev().slideUp("200").remove();
}, 4000);
}
modal_.modal("hide");
}, "json");
});
break;
default:
console.log("No action assigned! Please inform IT department!");
modal_.find("#confirmed").hide();
modal_.find(".modal-body").html("No action assigned! Please inform IT department!");
break;
};
});
// reset modal
$("#action_modal").on('hidden.bs.modal', function (event) {
const modal_ = $(this);
modal_.removeData();
modal_.find(".modal-title").html("");
modal_.find(".modal-body").html("");
});
})
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<!-- start of a modal -->
<div class="modal fade" id="action_modal" tabindex="-1" role="dialog" aria-labelledby="action_modal_label" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="action_modal_label">Popup</h5>
</div>
<div class="modal-body">
<h4 class="text-zenter"></h4>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">cancel</button>
<button type="button" class="btn btn-primary" id="confirmed">ok</button>
</div>
</div>
</div>
</div>
<!-- end modal -->
<span class="glyphicon glyphicon-trash remove_comment_btn" id="remove_comment_btn_1790"
data-toggle="modal" data-target="#action_modal" data-href="/do_delete/" data-row="1790"
data-action="approve_remove"
data-modal_title="Agreement"
data-modal_body="are you sure you want to delete?"
aria-selected="false" aria-hidden="true"> Delete 1790</span>
<br />
<span class="glyphicon glyphicon-trash remove_comment_btn" id="remove_comment_btn_1791"
data-toggle="modal" data-target="#action_modal" data-href="/do_delete/" data-row="1791"
data-action="approve_remove"
data-modal_title="Agreement"
data-modal_body="are you sure you want to delete?"
aria-selected="false" aria-hidden="true"> Delete 1791</span>
Expectation
My problem is - I need it to be reset each time cancel is clicked! Any ideas?
UPDATE
It seams to affect ALL modals. As soon as you open one of the similar modals, it will start piling data up and affect all you previously opened.

It's been a while up and no-one has solution. Luckily, I found one. And it's fairly simple. Problem is action binding for click: each time the modal is opened, new event for click is built, but never will never go off until action/event is completed or page refresh. So solution is simple - add off for click before on! No point to copy ALL the code from above, so just the trouble part!
...
case "approve_remove":
const elem_ = button_.parent().parent();
modal_.find(".modal-body").html(`${question_}`);
$("#confirmed").off("click");
$("#confirmed").on("click", function(e) {
...
And that will fix all double, triple, etc. events piling up on modal cancel/close!

Related

Bootstrap 4 - .modal is not a function

I'm using plain Javascript along with Bootstrap, and am getting this error. I've looked at many different questions and none seem to work for me. I downloaded Jquery, Popper, and Bootstrap with npm, and have added the min scripts at the bottom of my body:
<div id="success-delete" class="modal fade" 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">Success!</h4>
</div>
<div class="modal-body">
<p>Template successfully deleted.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<script src="/js/jquery.min.js" defer></script>
<script src="/js/popper.min.js" defer></script>
<script src="/js/bootstrap.min.js" defer></script>
<script src="/js/template-section.js" defer></script>
As you can see, I'm loading the jquery before bootstrap. When a function is called in my Javascript, I want the modal to appear:
/* template-section.js */
class TemplateSection {
constructor(...) {
...
this.successModal = document.querySelector('#success-delete');
}
_removeTemplate(e) {
const success = this.deleteCallback(e.currentTarget.previousSibling.getAttribute('src'));
if (success) {
this.container.removeChild(e.currentTarget.parentNode);
this.successModal.modal('show');
} else {
// do something
}
}
}
I've also tried changing the modal options to {show : true}, but that's not working. Printing out this.successModal gives me the correct element, but it doesn't appear to have the function modal.
Edit: I also know for a fact that the bootstrap.min.js file I have has modals included - I tried activating the modal by a button click and it works fine. It's getting the javascript to recognize the modal that's the problem.
Edit 2: Fixed! See answer below.
Fixed by using $('#success-delete') instead of the object declared from documentSelector. Not really sure why, but it's working!

Javascript waiting result of modal

I have a simple question about javascript and bootstrap modal. I have a wizard where I use file upload form, so I check the name of the file and if it doesn't contains some string I have to show a modal where ask if you want to continue anyway. How can I know which button is clicked into modal from javascript or jquery?
I have this code:
if (index==3){
var fileControl = document.getElementById('file');
//Check if the datatable name contains idFLeet and IdCar. REturn -1 if it not contains the string
if (fileControl.files[0].name.indexOf($("#selectedFleet").val()) > -1 && fileControl.files[0].name.indexOf($("#selectedCar").val()) > -1){
//File contains id so you can continue the upload
uploadFunction();
}
else{
$('#warningDatatableModal').modal("show");
//If click on Yes call uploadFunction
//If click on No return false
}
}
HTML modal code:
<div class="modal" id="warningDatatableModal" data-backdrop="static" data-keyboard="false">
<div class="modal modal-warning">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Warning</h4>
</div>
<div class="modal-body">
<p>There is a incongruity between file name and fleet and
car previously selected. Are you sure to continue?</p>
</div>
<div class="modal-footer">
<button id="close" type="button" class="btn btn-outline pull-left"
data-dismiss="modal">Close</button>
<button id="continueButton" type="button" class="btn btn-outline">Continue</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
</div>
After Yeldar Kurmangaliyev advice I have update my code but the wizard go ahed to the next tab instead of waiting into actual tab
if (index==3){
var fileControl = document.getElementById('file');
//Check if the datatable name contains idFLeet and IdCar. REturn -1 if it not contains the string
if (fileControl.files[0].name.indexOf($("#selectedFleet").val()) > -1 && fileControl.files[0].name.indexOf($("#selectedCar").val()) > -1){
//File contains id so you can continue the upload
uploadFunction();
}
else{
$('#warningDatatableModal').modal("show");
$(".modal-footer > button").click(function() {
clicked = $(this).text();
$("#warningDatatableModal").modal('hide');
});
$("#warningDatatableModal").on('hide.bs.modal', function() {
if (clicked === "Cancel"){
return false;
}else {
uploadFunction();
}
});
}
}
If I put this code out of wizard works(it doesn't close modal with cancel button because I use return false that needs for my wizard), but I need to stop wizard waiting modal result.
You can simply attach events to your buttons.
However, the user may want to close the window without action. The design of modal UI and its overlay suggests to click outside the window and close it.
In order to create an event which will fire event always when a user closes your modal, you need to attach to hide.bs.modal event:
$('#warningDatatableModal').on('hide.bs.modal', function() {
});
Here is the working JSFiddle demo.
You can try using the ids of the buttons and attaching a listener to see when they have been clicked like so:
$('#close').on('click',function(){
//do something
});
$('#continueButton').on('click',function(){
//do something
});

show bootbox over modal dialog

I have modal dialog like this one
<div id="tenantDialog" class="modal fade" tabindex="-1" data-backdrop="static">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">
<i class="fa fa-users"></i>
<spring:message code="label.tenant.person.title"/>
</h4>
</div>
<div class="modal-body">
<%--We load here the persons table here to be reloaded in any moment--%>
<div id="personTableDiv">
<c:set var="preferredCollaborators" value="${preferredCollaborators}" scope="request"/>
<jsp:include page="personsTable.jsp"/>
</div>
</div>
<div class="modal-footer">
</div>
</div>
</div>
Then in the personsTable.js associate to the include page I have the logic to open a bootbox confirm. But my problem is, that this bootbox it´s showing under the modal dialog, so it´s not intractable.
Here my bootbox creation
bootbox.confirm(customText, function (confirmed) {
if (confirmed) {
var regularityDocumentsIds = [];
var i;
for (i = 0; i < selectedPersons.length; i += 1) {
regularityDocumentsIds.push($(selectedPersons[i]).attr("data-preferredcollaboratorid"));
}
removePersons(regularityDocumentsIds);
}
});
Any idea what can I do to show this bootbox over the modal dialog?
This is a confirmed issue: using bootbox.confirm() within a bootstrap modal.
You have a workaround. Add this in your CSS:
.bootbox.modal {z-index: 9999 !important;}
my humble (working in production) solution
You should edit bootbox, look for the callback of:
dialog.one("hidden.bs.modal", function (e) {
// ensure we don't accidentally intercept hidden events triggered
// by children of the current dialog. We shouldn't anymore now BS
// namespaces its events; but still worth doing
if (e.target === this) {
dialog.remove();
}
});
and change it to:
dialog.one("hidden.bs.modal", function (e) {
// ensure we don't accidentally intercept hidden events triggered
// by children of the current dialog. We shouldn't anymore now BS
// namespaces its events; but still worth doing
if (e.target === this) {
dialog.remove();
}
// inspired by : https://github.com/makeusabrew/bootbox/issues/356#issuecomment-159208242
// if there is another modal, stop the event from propgating to bootstrap.js
// bootstrap.js uses the same event to remove the "modal-open" class from the body, and it creates an unscrolable modals
if ($('.modal.in').css('display') == 'block') {
// do not notify bootstrap about this change!!
e.stopPropagation();
}
});

Check if Bootstrap Modal currently Show

I'm trying to combine the Keypress plugin with Modal dialogs in Bootstrap. Based on this question, I can check if modal is open or closed using jquery.
However, I need to execute Keypress only if modal is closed. If it's open, I don't want to listen for keypresses.
Here's my code so far:
if(!$("#modal").is(':visible')) {
var listener = new window.keypress.Listener();
listener.simple_combo("enter", function() {
console.log('enter');
});
// I have over 20 other listeners
}
It's probably easier to leave the listeners attached and then conditionally exit them if the modal is open.
You could setup something like this:
var modalIsOpen = false
$('#myModal').on('shown.bs.modal', function(e) { modalIsOpen = true;})
$('#myModal').on('hidden.bs.modal', function(e) { modalIsOpen = false;})
Then just copy and paste the following line into all of your listeners.
if (modalIsOpen) return;
Demo in Stack Snippets
var modalIsOpen = false
$('#myModal').on('shown.bs.modal', function(e) { modalIsOpen = true;})
$('#myModal').on('hidden.bs.modal', function(e) { modalIsOpen = false;})
var listener = new window.keypress.Listener();
listener.simple_combo("s", function() {
if (modalIsOpen) return;
alert("You hit 's'");
});
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
<script src="http://cdn.rawgit.com/dmauro/Keypress/master/keypress.js"></script>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Don't Act On Key Presses</h4>
</div>
<div class="modal-body">
Try Hitting S
</div>
</div>
</div>
</div>
<p>Try Hitting S</p>
Bootstrap adds the in CSS class to a modal when it is open, thus (assuming your modal has id="modal":
var modalIsOpen = $('#modal.in').length > 0;

bootstrap 3 modal - javascript available multiple times

I am using bootstrap 3 modal dialogs with remote sources.
My Problem is that I use external JavaScript and script blocks in those remote sources. When I open and Close a modal Dialog and then reopen it, the JavaScript is loaded twice.
How can I suppress from loading the same JavaScript file again when reopening the modal Dialog? Or how can I destroy the loaded JavaScript when closing the Dialog?
JavaScript:
$(function() {
$('[data-load-remote]').on('click',function(e) {
e.preventDefault();
var $this = $(this);
var remote = $this.data('load-remote');
if(remote) {
$($this.data('remote-target')).load(remote);
}
});
});
HTML:
<a href="#myModal" role="button" class="btn" data-toggle="modal"
data-load-remote="http://localhost/dashboard/myprices"
data-remote-target="#myModal .modal-body">My Salon (Preview)</a>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
You can use another data- attribute to check whether it's loaded or not:
Add isloaded="false" to your anchor tag like so:
<a data-isloaded="false" href="#myModal" role="button" class="btn" data-toggle="modal"
data-load-remote="http://localhost/dashboard/myprices"
data-remote-target="#myModal .modal-body">My Salon (Preview)</a>
Then you can check if it's been loaded using $this.data('isloaded'). If it has, get out of there, if not, load it and set the flag like so: $this.data('isloaded', true).
Here's some JavaScript
$(function() {
$('[data-load-remote]').on('click',function(e) {
e.preventDefault();
var $this = $(this);
var remote = $this.data('load-remote');
if (!$this.data('isloaded')) {
if(remote) {
$($this.data('remote-target')).load(remote);
$this.data('isloaded', true)
}
}
});
});
jsFiddle
UPDATE for clarification based on comment
From the HTML5 spec on custom data attributes:
Every HTML element may have any number of custom data attributes specified, with any value.
i.e. There is no predefined data-isloaded, the same as there is no predefined data-load-remote. You could just as easily call it data-kylePromisesTheValueIsLoaded. As long as
that's the string you pass to the .data() method, then it will read / write the value for that attribute.

Categories

Resources