How To Align Table Columns Inside A Detail View With It's Parent Bootstrap-Table Columns In ASP.NET MVC
Good evening,
JavaScript function that perform's a POST operation to the MVC controller that returns a Partial View. It also adds the job number which is the unique ID for details view resizing if expand event is executed.
Collapse Event when executed removes the job number/unique id from the list of session for resizing.
MVC Action Result that queries the database and returns the Partial View page.
The Partial View page that is rendered in the Details View of the Bootstrap-Table.
Aligned Details View Child and Bootstrap-Table parent.
Cheers!
When working with Detail View option in Bootstrap-Table by Wenzhixin, there's a possibility that you have to render the details information using a table element to the detail view with same number of columns and headers of the parent table as per client request. However, upon rendering the details view with the table element, the child table's columns are not aligned with the parent Bootstrap-Table such as the sample screen below.
I tried different solutions such as CSS, jQuery/JavaScript and MutationObserver Pattern which work for a few details view and the rest would be in disarray. Before presenting the solution, here are the codes involved in this project.
Bootrap Table With data-detail-view property enabled.
<table id="tblDetailsReport" class="TableBorderCollapse table-striped" data-toggle="table" data-sort-name="JobNumber" data-sort-order="asc" data-search="true" data-show-columns="false" data-pagination="false" data-advanced-search="true" data-id-table="advancedTable" data-show-multi-sort="false" data-show-export="false" data-toolbar="#toolbar" data-click-to-select="true" data-url='@Url.Action("GetDetailsReportRecords", "ClientDashboard")' data-cookie="true" data-cookie-id-table="tblDetailsReportCookieID" data-page-size="25" data-striped="true" data-show-footer="true" data-detail-view="true" data-page-list="[25, 500, 1000, 10000, All]"> <thead> <tr> <th data-field="JobType" data-sortable="true" data-searchable="true" data-footer-formatter="DetailsReport.JobTypeFormatter">Job Type</th> <th data-field="SowBidNum" data-sortable="true" data-searchable="true" data-formatter="DetailsReport.SowBidFormatter">BID/SOW</th> <th data-field="PONum" data-sortable="true" data-searchable="true">PO</th> <th data-field="JobNumber" data-sortable="true" data-searchable="true" data-formatter="DetailsReport.ProjectLinkFormatter">Job Number</th> <th data-field="Description" data-sortable="true" data-searchable="true">Description</th> <th data-field="Rate" data-searchable="true" data-formatter="DetailsReport.RateFormatter" data-class="tdHrsRateAmtDetRpt">Rates</th> <th data-field="TotalHours" data-searchable="true" data-formatter="DetailsReport.HoursFormatter" data-class="tdHrsRateAmtDetRpt">Hours</th> <th data-field="Amount" data-sortable="true" data-searchable="true" data-formatter="DetailsReport.AmountFormatter" data-footer-formatter="DetailsReport.TotalFormatter" data-class="tdHrsRateAmtDetRpt">Amount</th> <th data-field="InvoiceStatus" data-sortable="true" data-searchable="true">Invoice Status</th> </tr> </thead> </table>
function GetReportDetails () { $('#tblDetailsReport').on('expand-row.bs.table', function (e, index, row, $detail) { var myURl = urlClientDetailsView; var data = JSON.stringify({ 'JobNumber': row.JobNumber }); //add job number to details view for resizing let job = row.JobNumber; if (sessionStorage.getItem("jobNumbersDetail") !== null && sessionStorage.getItem("jobNumbersDetail") !== undefined) { let sObject = sessionStorage.getItem("jobNumbersDetail").split(","); if (sObject.length > 0) { if (sObject.indexOf(job) == -1) { sObject.push(job); sessionStorage.setItem("jobNumbersDetail", sObject); } } } else { let sObject = []; sObject.push(job); sessionStorage.setItem("jobNumbersDetail", sObject); } $.ajax({ type: 'POST', url: myURl, contentType: "application/json; charset=utf-8", data: data, success: function (data, status, xhr) { $detail.html(data); }, error: function (xhr, status, error) { alert('An error occured. Please run the Details Report Again.'); } }); }); };
function CollapseReportDetails () { $('#tblDetailsReport').on('collapse-row.bs.table', function (e, index, row, $detail) { let job = row.JobNumber; //remove job number from details view for resizing if (sessionStorage.getItem("jobNumbersDetail") !== null && sessionStorage.getItem("jobNumbersDetail") !== undefined) { let sObject = sessionStorage.getItem("jobNumbersDetail").split(","); if (sObject.length > 0) { if (sObject.indexOf(job) !== -1) { let idx = sObject.indexOf(job); sObject.splice(idx, 1); sessionStorage.setItem("jobNumbersDetail", sObject); } } } }); };
[Authorize] [HttpPost] public PartialViewResult GetDetailReportDetailView(string project) { clsClientModel model; //Codes to retrieve data from the database... return PartialView("../ClientDashboard/DetailsReportDetailView", model); }
@{ Layout = ""; } @model List<JobActivities> <style type="text/css"> .tblDetailView { width: 100% !important; margin: 0px !important; } #divViewDetailContainer { display: flex; justify-content: center; padding: 0; } .detail-view > td{ padding: 2px !important; } </style> <div id="divViewDetailContainer"> <table class="tblDetailView table table-condensed table-bordered table-striped"> <thead> <tr> <th class="tdJType"></th> <th class="tdBid"></th> <th class="tdPo"></th> <th class="tdJob"></th> <th class="tdAct"></th> <th class="tdRate"></th> <th class="tdHrs"></th> <th class="tdAmt"></th> <th class="tdIst"></th> </tr> </thead> <tbody> @for (int i = 0; i < Model.Count; i++) { if (Model[i].isShowInDetail) { <tr> <td></td> <td></td> <td></td> <td></td> <td>@Model[i].ActivityName</td> <td style="text-align:right">@Model[i].RateDisplay</td> <td style="text-align:right">@Model[i].Hours</td> <td style="text-align:right">@Model[i].AmountDisplay</td> <td></td> </tr> } } </tbody> </table> </div>
After trying several times, I finally solved the task by revising the Partial View page above. First, I set the id of the table element with a job number or other unique values might help. Next is I created a function that obtains the job number/unique value which is the id of the table and the width of each Bootstrap Table column headers thru it's class or data-field property and use those values to set the widths of the Partial View table columns. See html markup of the table in Bootrap Table With data-detail-view property enabled. with the data-field names. After that, the columns in the child table are now aligned with the parent table. This also works when the page is resized. The revised Partial View page markup is shown below.
@{ Layout = ""; } <style type="text/css"> .tblDetailView { width: 100% !important; margin: 0px !important; } #divViewDetailContainer { display: flex; justify-content: center; padding: 0; } .detail-view > td{ padding: 2px !important; } </style> <script> $(function () { OnDetailsViewInitLoad(); $(window).resize(function () { //resize details tables if (sessionStorage.getItem("jobNumbersDetail") !== null && sessionStorage.getItem("jobNumbersDetail") !== undefined) { let sObject = sessionStorage.getItem("jobNumbersDetail").split(","); if (sObject.length > 0) { for (var i = 0; i < sObject.length; i++) { DynamicDetailsSizing(sObject[i]); } } } }) }); function OnDetailsViewInitLoad() { let modelCount = @Html.Raw(@Model.Count); if (parseFloat(modelCount) <= 0 || modelCount == undefined || modelCount == '' || modelCount == null) { alert('An error occured. Please run the Details Report Again.'); } else { try { let jobNum = '@Html.Raw(@Model[0].JobNumber)'; DynamicDetailsSizing(jobNum); } catch (err){ alert('An error occured. Please run the Details Report Again.'); } } } function DynamicDetailsSizing(jobNum) { $('#' + jobNum + ' .tdJType').width(parseFloat($("[class=detail]").width()) + parseFloat($("[data-field=JobType]").width())); $('#' + jobNum + ' .tdBid').width(parseFloat($("[data-field=SowBidNum]").width())); $('#' + jobNum + ' .tdPo').width(parseFloat($("[data-field=PONum]").width())); $('#' + jobNum + ' .tdJob').width(parseFloat($("[data-field=JobNumber]").width())); $('#' + jobNum + ' .tdAct').width(parseFloat($("[data-field=Description]").width())); $('#' + jobNum + ' .tdRate').width(parseFloat($("[data-field=Rate]").width())); $('#' + jobNum + ' .tdHrs').width(parseFloat($("[data-field=TotalHours]").width())); $('#' + jobNum + ' .tdAmt').width(parseFloat($("[data-field=Amount]").width())); $('#' + jobNum + ' .tdIst').width(parseFloat($("[data-field=InvoiceStatus]").width())); } </script> @model List<JobActivities> <div id="divViewDetailContainer"> <table id="@Model[0].JobNumber" class="tblDetailView table table-condensed table-bordered table-striped"> <thead> <tr> <th class="tdJType"></th> <th class="tdBid"></th> <th class="tdPo"></th> <th class="tdJob"></th> <th class="tdAct"></th> <th class="tdRate"></th> <th class="tdHrs"></th> <th class="tdAmt"></th> <th class="tdIst"></th> </tr> </thead> <tbody> @for (int i = 0; i < Model.Count; i++) { if (Model[i].isShowInDetail) { <tr> <td></td> <td></td> <td></td> <td></td> <td>@Model[i].ActivityName</td> <td style="text-align:right">@Model[i].RateDisplay</td> <td style="text-align:right">@Model[i].Hours</td> <td style="text-align:right">@Model[i].AmountDisplay</td> <td></td> </tr> } } </tbody> </table> </div>
Cheers!
Comments
Post a Comment