Jump to content

How to show Bulk Edit pop-up within Bootstrap 5 Modal - when datapage is embedded in modal div


Recommended Posts

Hi all,

I wanted to share a solution I came up with, which might be helpful for you. 

Problem:

I have recently been trying to streamline page loading times, and one of the ways I've done this is to move record update datapages to Bootstrap 5 modals. It was working great for me with single record update datapages embedded in modals, but when it came to a report datapage, with a bulk edit feature, I was stumped. See the attached image. Basically, when I clicked the edit button, the pop-up for bulk edit would show up, but it would be BEHIND the modal (see my attached screenshot). Since I have my modal set to static background, that basically meant I wasn't able to edit anything in the pop-up window until I closed the modal. Not helpful!

Solution:

Use jQuery to assign a .click() handler to any bulk edit buttons in my datapage that is embedded in the modal. The .click() handler will wait half a second (to give the bulk edit pop-up time to be written to the page), then it will move the bulk edit pop-up div to inside the modal body. 

This solution is only for situations where you're including jQuery and Bootstrap 5. 

Here's my html modal, which lives at the bottom of my html page where the first datapage is embedded:

    <div class="modal fade" id="cb-modal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="imgModalLabel" aria-hidden="true">
        <div id="cb-modal-dialog" class="modal-dialog modal-larger-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="cb-modal-title">Modal title</h5>
                    <button type="button" class="btn-close bg-transparent" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <div id="cb-modal-body" class="cb-form-fluid cb-form-resp"></div>
                </div>
            </div>
        </div>
    </div>

The datapage that is embedded in that html page happens to be a report style datapage. Every record includes a link which will dynamically embed a second datapage in my modal, and open it. Complete with params. Here is the code for one of my links:

  <a href="#" role="button" data-bs-toggle="modal" data-bs-target="#cb-modal"
      onclick="openModal(
      'Edit/Add Items', 
      '1dae6000bcb0b9a06b9841e2a9c0', 
      '?cbResetParam=1&garments_CustomerInvoiceNo=[@field:PSST_CustomerInvoiceNo]&garments_TrackingNo=[@field:PSST_TrackingNo]&garments_Order_id=[@field:PSST_workOrder_id]&garments_CustCode=[@field:Garments_Items_CustCode]&garments_ShipVia=[@field:Garments_Items_ShipVia_endcodedForURL]&garments_ShipDate=[@field:PSST_ShipDate]&garments_Distributor=[@field:Garments_Items_Distributor_encodedForURL]&garments_Whse=[@field:PSST_Whse]&garments_CustomerName=[@field:Garments_Items_CustomerName_encodedForURL]&garments_CustomerPO=[@field:Garments_Items_CustomerPO_encodedForURL]&garments_CustomerAccount=[@field:Garments_Items_CustomerAccount]'
    );">Edit/Add Items</a>

Here is my function for openModal(), saved in an external javascript file, which is included with my html page:

    // function - deploy DP in modal
    function openModal(modalTitleappKeyparams)
    {
        $('#cb-modal-body').html('');
        deployDP('cb-modal-body'appKeyparams);
 
        $('#cb-modal-title').html(modalTitle);
 
        // draggable modal
        $(".modal-header").on("mousedown"function(mousedownEvt) {
            var $draggable = $(this);
            var x = mousedownEvt.pageX - $draggable.offset().left,
            y = mousedownEvt.pageY - $draggable.offset().top;
 
            $("body").on("mousemove.draggable"function(mousemoveEvt) {
                $draggable.closest(".modal-content").offset({
                    "left": mousemoveEvt.pageX - x,
                    "top": mousemoveEvt.pageY - y
                });
            });
 
            $("body").one("mouseup"function() {
                $("body").off("mousemove.draggable");
            });
 
            $draggable.closest(".modal").one("bs.modal.hide"function() {
                $("body").off("mousemove.draggable");
            });
        });
    }
 
    function deployDP(containerIDappKeyparams)
    {
        var params = params || '';
        var dataPageScript = document.createElement("script");
        var container = document.getElementById(containerID);
        dataPageScript.src = cbDataPagePrefix + appKey + '/emb' + params;
 
        container.innerHTML = '';
        container.appendChild(dataPageScript);
    }

Finally, in the Footer in the Configure Results Page Fields section of my second datapage - the one that is embedded dynamically within the modal - I have this code:

<script type="text/javascript">
 
    document.addEventListener('DataPageReady'function (event) {
 
        $('#cb-modal .cbResultSetBulkEditActionLink').click(function () {
            setTimeout(function () { // gives the bulk edit update form time to load
                if (document.getElementById('BulkUpdateForm') && document.getElementById('cb-modal')) {
                    $('#cb-modal div.modal-body').append($('#BulkUpdateForm')); // moves the bulk edit update form inside the modal body, thereby making it editable while the modal is open.
                }
            }, 500);
        });
 
        $('#cb-modal .cbResultSetBulkDeleteActionLink').click(function () {
            setTimeout(function () { // gives the delete confirmation time to load
                if (document.getElementById('Alert') && document.getElementById('cb-modal')) {
                    $('#cb-modal div.modal-body').append($('#Alert')); // moves the delete confirmation alert inside the modal body.
                }
            }, 500);
        });
 
    });
 
</script>

I know this is a really specific example, but it seemed to me like something that could come up for other people, so I figured I'd share!

Hope this is helpful.

Screenshot 2021-08-30 132000.jpg

Edited by melsenc
Added code to make delete alert pop-up also show
Link to comment
Share on other sites

  • 3 months later...

Hello melsenc,

Thank you for sharing this.  It was very helpful to me in building my own varying modal content.  If anybody else is using bootstrap 5 and just wants the functionality of dynamically embedding scripts to a modal (say, to vary a single record update DataPage), I made it work using the data-bs-* attributes framework shown here: https://getbootstrap.com/docs/5.0/components/modal/#varying-modal-content.  This revision removes the need for jquery (removed from bootstrap 5) but also removes the functionality that melsenc had of dragging the modal and allowing bulk edit on a report DataPage.  Once my js improves maybe I can add those in (I'm still very novice, as you more experienced programmers may detect in my code).

I've also added a few clarifications if you were trying to get the code melsenc posted to work.  Unless I am mistaken (very real possibility) what melsenc's code does is reconstruct an embed script with parameters already set.

My HTML code for the modal generally mirrors that of melsenc, only revisions are the class for the modal size is "modal-lg" instead of "modal-larger-dialog":

<div class="modal fade" id="cb-modal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
    aria-labelledby="cb-modal-title" aria-hidden="true">
    <div id="cb-modal-dialog" class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="cb-modal-title">Modal title</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <div id="cb-modal-body"></div>
            </div>
        </div>
    </div>
</div>

My anchor element (link) code in the HTML Block field of my tabular report is below.  You will notice that I'm not using onclick to call the function and pass function parameters, but rather passing the info as data-bs-* attributes to the function triggered by the event listener.  You may also notice that what melsenc has named appKey I have named data-bs-dpkey, which is the 28-character string that identifies the DataPage you want to embed in the modal.  You can get this string from the embed script when you deploy the DataPage--it's the string between "/dp/" and "/emb".  For security purposes, I have replaced the actual string with "###..."

<a data-bs-dpkey="############################" 
   data-bs-param="?cbResetParam=1&amp;parameterNameYouArePassing=[@field:parameterFieldYouArePassing]" 
   data-bs-target="#cb-modal" data-bs-title="Title You Want for the Modal" 
   data-bs-toggle="modal" href="#">Edit Something</a>

My javascript is kept in an external file and it basically follows the structure shown in the bootstrap 5 documentation.  As I said, it doesn't (yet) have the functionality of a draggable modal or the delay melsenc wrote to deal with the bulk edit issue.  One thing I couldn't find in melsenc's code is where the variable cbDataPagePrefix was defined.  I'm assuming this is the prefix that defines your caspio account so it would make sense to not show where it is defined.  I defined my account in the function (replaced with ######## in this example).  Perhaps there is a better way to handle this?

var Modal = document.getElementById('cb-modal');
Modal.addEventListener('show.bs.modal', function (event) {
// Button that triggered the modal
var button = event.relatedTarget
// Extract info from data-bs-* attributes
let newModalTitle = button.getAttribute('data-bs-title');
let datapageKey = button.getAttribute('data-bs-dpkey');
let params = button.getAttribute('data-bs-param');
// If necessary, you could initiate an AJAX request here
// and then do the updating in a callback.
//
// Update the modal's content.
var modalTitle = Modal.querySelector('#cb-modal-title');
var modalBodyInput = Modal.querySelector('#cb-modal-body');
var dataPageScript = document.createElement("script");
var cbDataPagePrefix = "https://########.caspio.com/dp/";

dataPageScript.src = cbDataPagePrefix + datapageKey + '/emb' + params;
modalTitle.textContent = newModalTitle;
modalBodyInput.innerHTML = '';
modalBodyInput.appendChild(dataPageScript)
})

Hope this helps someone! 

Link to comment
Share on other sites

  • 4 months later...
  • 3 months later...

Hello @melsenc, this is a good solution!  I have encountered this issue as well when I put my results page in a modal and I just added some CSS to resolve it. In my solution, I used the position and  z-index property to show the bulk edit form in front of my modal.

<style>
#BulkUpdateForm {
position: fixed !important;
z-index: 999 !important;
}
</style>

 

Link to comment
Share on other sites

Just to add, if ever you encounter another issue about bulk update form fields being unclickable, then you may insert the code below inside the footer of results page. This is also an issue in Bootstrap where the modal steals the focus of other elements, hence they are unclickable.

<script>
      $(document).off('focusin.modal');
</script>

Here is the thread I used as a reference: https://stackoverflow.com/questions/38568621/cannot-type-or-even-focus-in-input-type-text-while-bootstrap-modal-is-open/38614737#38614737

Link to comment
Share on other sites

  • 2 months later...

Hi all, 
I had the similar issue as GoodBoy but with the Inline Delete modal window that was not visible. I added the following modifications to the DataPage with the modal. 

Header:

<style>
#Alert{
position: fixed !important;
z-index: 1100 !important;
}
</style>

Footer:

<script type="text/javascript">
    $('.cbResultSetActionCell a').on('click', function(e) {
        const myInterval = setInterval(
            function() {
                if($("#Alert .ActionButton").length !=0 ){
                    $('#Alert .ActionButton').on('click', function(e) {
                        $("#cb-modal").modal('hide');
                    })
                    clearInterval(myInterval);
                }
            }
        , 100);
    })
</script>
Link to comment
Share on other sites

  • 1 month later...

Hi! Just an update - if you have a modal that is showing behind the Results Page, you can use this code in the Header:

<style>

.modal {
 z-index: 9999 !important;
}

</style>

In addition, if you would like to automatically adjust the size of the modal based on its content. You can use this code in the Header as well:

<style>

body .modal-dialog { /* Width */
max-width: 50%;
width: auto !important;
}

</style>

 

Link to comment
Share on other sites

  • 2 months later...

Hello - In addition to the previous post, if you have a modal and Form Elements that are not showing such as AutoComplete, Dropdowns, and Date Pickers, you can use a custom CSS to show these elements in front of the modal.

Insert this code in the Header of the DataPage.

<style>

.modal-backdrop{
z-index:4 !important;
}
.modal {
z-index: 5 !important;
}
.header-navbar{
z-index: 3 !important;
}

</style> 

 

Link to comment
Share on other sites

  • 4 months later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...