Donate

How To Align Table Columns Inside A Detail View With It's Parent Bootstrap-Table Columns In ASP.NET MVC

Good evening,

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.
How To Align Table Columns Inside A Detail View With It's Parent Bootstrap-Table In ASP.NET MVC
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>
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.
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.');
		}
	 });
  });
};
Collapse Event when executed removes the job number/unique id from the list of session for resizing.
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);
		   }
		}
	 }
  });
};
MVC Action Result that queries the database and returns the Partial View page.
[Authorize]
[HttpPost]
public PartialViewResult GetDetailReportDetailView(string project)
{
	 clsClientModel model;
	 
	 //Codes to retrieve data from the database...

	 return PartialView("../ClientDashboard/DetailsReportDetailView", model);
}
The Partial View page that is rendered in the Details View of the Bootstrap-Table.
@{
   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>
Aligned Details View Child and Bootstrap-Table parent.
How To Align Table Columns Inside A Detail View With It's Parent Bootstrap-Table In ASP.NET MVC

Cheers!

Comments

Donate

Popular Posts From This Blog

WPF CRUD Application Using DataGrid, MVVM Pattern, Entity Framework, And C#.NET

TypeScript Error Or Bug: The term 'tsc' is not recognized as the name of a cmdlet, function, script file, or operable program.

Invalid nested tag div found, expected closing tag input