Datatable Column Mis-Alignment - datatables

Stack: Bootstrap 5, JQuery, Datatables
The issue: I have a page that uses Bootstrap navtabs. In one tab is a chart, and in another tab is a table created using Datatables. When the table tab has focus, the table styling is fine, even when the data changes. However, whenever another tab has focus and the data changes, the columns in the table cease to be aligned correctly. I think part of the issue is that some of the column titles are dynamic, with dynamic content demarcated by spans.
The data is controlled by a series of select menus, so whenever one of the select menus changes a series of processes is triggered, which includes updated the dynamic content and also refreshing the datatable.
I am not applying any custom classes or additional styling to the table. It looks like the issue is the datatable object trying to calculate col widths properly
Here's an example of the column headers not aligning properly:
Has anyone encountered this before, or have any ideas for how to fix this problem?
HTML:
<!-- Container for dynamic datatables -->
<div class="col-sm-12">
<div class="table-responsive">
<table id="datatable" class="table table-striped table-hover table-bordered table-sm" aria-label="Graduation Rates by Year" style="width:100%">
<thead>
<th>Cohort Year</th>
<th>Ethnicity</th>
<th>Pell Status</th>
<th>1st Gen. Status</th>
<th>Gender</th>
<th>Student Sub-Group: Count Enrolled</th>
<th>Student Sub-Group: Count Graduating within <span class="outcomeYear">6</span>-years
</th>
<th><span class="campus-system">Campus</span>-wide <span class="outcomeYear">6</span>-Year
<span class="outcomeTypeAbbr">Grad.</span> Rate
</th>
<th>Student Sub-Group: <span class="outcomeYear"></span>-Year <span class="outcomeTypeAbbr">Grad.</span> Rate</th>
<th>Gap (Difference from <span class="campus-system">Campus</span> Grad Rate)</th>
</thead>
<tbody></tbody>
</table>
</div>
</div>
JQuery:
//Initialize datatable
table = $('#datatable').DataTable({
cache: false,
scrollCollapse: false,
paging: true,
scrollX: true,
pagingType: 'simple_numbers',
lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, 'All']],
searching: false,
info: false,
processing: true,
serverSide: true,
stateSave: true,
ajax: {
url: apiURL + '/table-data/',
data: function (d) {
d.campus = $campus.val();
d.studentType = $studentType.val();
d.cohort = $cohort.val();
d.outcomeType = outcomeType;
d.outcomeYear = outcomeYear;
d.outcomeTypeAbbr = outcomeTypeAbbr;
d.maxCohort = maxCohort;
}
}
});
JQuery for data change:
/* I have tried moving the dynamic text updates to before the table reload, and also using drawCallback to do these steps upon table draw. Neither changes anything. */
//Reload datatable
table.ajax.reload();
//Update dynamic text
$('.campus').html($campus.val());
$('.studentType').html($studentType.val());
$('.outcomeType').html(outcomeType);
$('.outcomeTypeAbbr').html(outcomeTypeAbbr);
$('.outcomeYear').html(outcomeYear);
$('.campus-system').html(cTxt);

This answer is actually from user andrewJames. He gave a possible solution in the comments that worked, but is declining to make it the solution.
The reason the column headers were misaligned when the data loaded while the focus was on another tab is that DataTables needs a visible viewport to calculate column widths. andrewJames's suggestion, which I tried with success was to add a table redraw to the tab on an oblick event.
Bootstrap's version of an onlick event for a navtab is actually the "shown.bs.tab" event. Here is my implementation of the solution:
/**
* When a tab is clicked.
*/
$(document).on('shown.bs.tab', '.dashboard-nav-link', function(e){
if(e.target.id == 'datatables_tab')
table.draw('page');
});

Related

show/hide div on the bases of which box div clicked in Vuejs. check image for better understanding

This is an image of table i created(ignore dates in header)
Functionality I want
when a user click on a specific box dialog open and get some value which will decide whether to put tick or cross in that box. Let's say i clicked on a box in first column(27/07/2020) and third row(asdf)
then tick should be shown in that box.
Here is table I'm creating
<table class="table table-bordered">
<thead class="table_header">
<tr >
<th scope="col" class="text-center table_th" >Medications</th>
<template v-for="head in table_headers_data" >
<th scope="col" class="text-center table_th" >{{head.day}} {{head.date}}</th>
</template>
</tr>
</thead>
<tbody>
<template v-for="item in active_medications" >
<tr :key="item.uuid">
<th class="cust-border" scope="row">{{item.title}}</th>
<td v-for="(date_item, index) in table_headers_data" #click="boxClicked(item,date_item)" :key="index" >
//here is code where i am trying to show tick or cross on the basis of user input in that box and
<div v-show="selected_box==date_item.day+item.uuid+'-tick'" class="text-center" >
<v-icon color="green">mdi-check</v-icon>
<!-- <v-icon v-if="showCross==true" color="red">mdi-close</v-icon> -->
</div>
<div v-show="selected_box==date_item.day+item.uuid+'-cross'" class="text-center" >
<!-- <v-icon v-if="showTick==true" color="green">mdi-check</v-icon> -->
<v-icon color="red">mdi-close</v-icon>
</div>
</td>
</tr>
</template>
</tbody>
</table>
boxClicked function just get object of an item of medicine and data related to dates information.. then i store that data in firebase. problem i don't know how to show tick/cross in that specific box. its like a user take medicine or not on that date. if it takes medicine according to data i have to show tick or cross in that box corresponding to that medicine and date.
here is boxClicked function code
boxClicked(medicine,date_data){
this.checkbox_dialog = true;
this.administered_dialog = true;
this.medicine_detail.med_date = date_data.date;
const today = new Date();
//const date = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate();
const time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
//const dateTime = date +' '+ time;
this.medicine_detail.med_time = time;
this.medicine_detail.med_day = date_data.day;
this.medicine_detail.med_uuid = medicine.uuid;
this.medicine_detail.user_email = this.user_email
/*console.log(this.medicine_detail)
let as = date_data.day+medicine.uuid;
console.log('as = '+as)*/
},
save_medicine_record function
this function is called when someone click on box and dialog open and user select it's value and click OK button . on click of OK button this function is called.
in the response of axios request i'm show tick/cross in that perticular box
save_medicine_record(status){
let api_token = this.user.api_token
axios.post('api/save_medicine_record?api_token='+api_token,this.medicine_detail)
.then(response => {
console.log('response = ')
console.log(response)
if(this.medicine_detail.status=='non_administered'){
console.log('in respose cross')
this.selected_box=this.medicine_detail.med_day+this.medicine_detail.med_uuid+'-cross'
// this.showCross = true;
}
else if(this.medicine_detail.status=='administered'){
console.log('in respose tick')
this.selected_box=this.medicine_detail.med_day+this.medicine_detail.med_uuid+'-tick'
//this.showTick = true;
}
//this.table_headers_data=[];
})
.catch(err=>{
console.log(err)
/*this.snackbar_error = true
this.snackbar_text = err.response.data.message*/
})
},
I tried to give id to the div in like :id="date_item.day+item.uuid"
and other way i tried is in above code.
Everything is working fine when i store data in firebase and get result from axios i want to put tick or cross in that specific location..
Problem now facing
after many tries i am able to show tick/cross on the basis of user input but then when i try to enter value in other box then it removes previous clicked box and show just one box value(tick/cross icon div).
I also tried to create data variables dynamically in a thinking to give that v-if true and false. but unable to reach that point.
Please please guide me how to achieve functionality because i spent many days on it.
I posted this question 10 days ago but did not get any solution so that is why i am posting it again
Pics of dialogs when a box is clicked
Use an array of selected boxes, Try this for tick and same for cross
//you can use a Map() [--dictionary] object here
this.selected_box_array.push(this.medicine_detail.med_day+this.medicine_detail.med_uuid+'-tick')
<!-- <v-icon v-if="showTick==true && selected_box_array.indexOf(date_item.day+item.uuid+'-tick')" color="green">mdi-check</v-icon> -->

DataTable column width with select in th

Using Bootstrap 4 with DataTables. I have a hidden card containing a datatable. When loading the page if a saved preference (to show the card containing the table) is checked then I show the card and then adjust the columns and draw:
a piece of $(document).ready:
/* code to create table here */
/* wait for the table initialization to finish before restoring card visibility */
$('#dashboardProfitsTable').on('init.dt', function(e, settings, json) {
$.when(
restorePrefs(currentPrefPage))
.done(function() {
/* did user leave this card visible last time? */
if ($('input[name=ShowProfit]').is(":checked")) {
$('#profitsCard').show();
dashboardProfitsTable.columns.adjust().draw();
}
});
});
and some relevant HTML:
<div id="profitsCard" class="card" style="display:none">
<div class="card-body pt-0 pb-2">
<table id="dashboardProfitsTable" class="table" style="width:100%">
<thead>
<tr>
<th></th>
<th><select id="column1" class="form-control"></select></th>
<th><select id="column2" class="form-control"></select></th>
<th><select id="column3" class="form-control"></select></th>
<th><select id="column4" class="form-control"></select></th>
</tr>
</thead>
After the show() the right side of the select in the right column (Last 30 Days) is clipped by a couple of pixels:
but if I resize the window width even 1 pixel (wider or narrower; doesn't matter) the table recalcs widths and redraws so the right side of the 4th is not clipped:
And after that initial window resize everything is fine at every width. It's just the initial show() that clips the rightmost select. Is there something I can do besides columns.adjust().draw() after show() to get the datatable to recalc as if it was doing a window resize recalc?

Datatables Responsiveness - Searchbar (bootstrap)

I have started to implement Datatables in a project.
My Project is based on Bootstrap 3.
I have build up a package with the necessary files on the datatables download-page and created a simple datatable based on the docs. Everything works fine, but I have a problem with responsiveness. Have a look at the following screenshot:
As you see. the search-bar has problems.
The table has the following HTML:
<table width="100%" class="table table-striped table-bordered dt-responsive table-condensed table-hover" id="event_history" cellspacing="0"> .......
The table has the following JS:
var table = $('#event_history').DataTable({
responsive: true,
colReorder: true,
lengthChange: true,
"order": [[ 0, "desc" ]],
});
Perhaps somebody can help me to solve this.
Thank you!
Controls in DataTables with Bootstrap styling wrap nicely when table occupies full page width, see this example.
However I think you're showing your table in a panel that doesn't occupy full page width, which prevents col- rules from being applied, as shown in this example. You can use special crafted value for dom option to configure column layout for one specific table based on your expected container sizes.
For example:
var table = $('#example').DataTable({
responsive: true,
dom:
"<'row text-center'<'col-xs-12'l><'col-xs-12'f>>" +
"<'row'<'col-xs-12'tr>>" +
"<'row text-center'<'col-xs-12'i><'col-xs-12'p>>"
});
See this example for code and demonstration.

Row Selection in Enhanced Grid

I am new to Dojo and i came across a problem that has me completely stumped. I am creating a data grid in Dojo with the Enhanced Grid .
Each row in the grid has a checkbox with which the row can be selected. The checkbox has been implemented using the indirectselection plugin.
Now when i select a row using the checkbox everything works fine. But when I select a row by clicking on other data cells the row does'nt get selected !
Heres the JSP part of the datagrid
<table data-dojo-id="grid" data-dojo-type="dojox.grid.EnhancedGrid" plugins="{indirectSelection: {headerSelector:true}, filter: true,pagination: true}"
data-dojo-props="store:icGrid,
clientSort:true " formatterScope="myFormatters"
style="width: 100%; height: 20em;">
<thead>
<tr>
<th width="25%" field="empNo" formatter="formatLink">empNo</th>
<th width="25%" field="name">name</th>
<th width="25%" field="email">email</th>
<th width="25%" field="phone">phone</th>
</tr>
</thead>
</table>
If I remove the code referring to indirect selection (plugins="{indirectselection...) the rows get selected when I click on other data cells (as they should). But I also need the checkbox that the indirectselection implements.
Is there a way to make the indirectselection work without taking away the row select functionality ?
Take a look at the grid in the page I will link below. I need a grid that works like that
(The last grid in the page with the checkboxes)
http://dojotoolkit.org/documentation/tutorials/1.8/working_grid/demo/selector.php
I managed to resolve the issue by 1. using the cellClick event to listen 2. Get the rowindex of the cell when it is clicked 3. set it to selected.
grid.on("CellClick", function(event)
{
var rowId = event.rowIndex;
grid.selection.setSelected(rowId, true);
grid.render();
}
grid.selection.getSelected(); did not return the selected rows and I am wondering if this is a compatibility issue ? It seems like when i use the indirectSelection plugin the row Select is behaving in unexpected ways.
Have you ever heard about DGRID .
I think you should check it.
It really works very good with dojo .
Here are some useful sites .
Dgrid Main webpage
Git hub Documentation
Use this code below to listen to grid selection and check what selectedRows return and use the index of that row to toggleRow
dojo.connect(grid, "onRowClick", function(e) {
var selectedRows= grid.selection.getSelected();
grid.rowSelectCell.toggleRow(selectedRows[i], true);
});
Simple code :- "SelectionChanged"` even is available. so code like this:-
grid.on("SelectionChanged", function(event)
{
var rowId = event.rowIndex;
grid.selection.setSelected(rowId, true);
grid.render();
}
The "SelectionChanged"` even is available. so code like this:-
grid.on("SelectionChanged", function(event)
{
var rowId = event.rowIndex;
grid.selection.setSelected(rowId, true);
grid.render();
}

How to close dojox.grid.DataGrid

I have a grid that populates from a search event and I'd like the option of being able to close the grid by simply adding an X in the top right corner, similar to how you close any browser or window. I thought it would be as easy as adding the X, styling it to my liking and then creating an onclick event that would close or hide the grid... but I can't seem to get that working. Any help would be appreciated.
My JS is:
dojo.require("dojox.grid.DataGrid"); //FindTask
dojo.require("dojo.data.ItemFileReadStore"); //FindTask
dojo.require("esri.tasks.find"); //FindTask
var findTask, findParams;
var grid, store;
var searchExtent;
function doFind() {
//Show datagrid onclick of search button and resize the map div.
esri.show(datagrid);
dojo.style(dojo.byId("content"), "height", "83%");
searchExtent = new esri.geometry.Extent ({
"xmin":-9196258.30121186,"ymin":3361222.57748752,"xmax":-9073959.055955742,"ymax":3442169.390441412,"spatialReference":{"wkid":102100}
});
map.setExtent(searchExtent);
//Set the search text to the value in the box
findParams.searchText = dojo.byId("parcel").value;
grid.showMessage("Loading..."); //Shows the Loading Message until search results are returned.
findTask.execute(findParams,showResults);
}
function showResults(results) {
//This function works with an array of FindResult that the task returns
map.graphics.clear();
var symbol = new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([98,194,204]), 2), new dojo.Color([98,194,204,0.5]));
//create array of attributes
var items = dojo.map(results,function(result){
var graphic = result.feature;
graphic.setSymbol(symbol);
map.graphics.add(graphic);
return result.feature.attributes;
});
//Create data object to be used in store
var data = {
identifier: "Parcel Identification Number", //This field needs to have unique values. USES THE ALIAS!!!
label: "PARCELID", //Name field for display. Not pertinent to a grid but may be used elsewhere.
items: items
};
//Create data store and bind to grid.
store = new dojo.data.ItemFileReadStore({ data:data });
var grid = dijit.byId('grid');
grid.setStore(store);
//Zoom back to the initial map extent
map.setExtent(searchExtent);
}
//Zoom to the parcel when the user clicks a row
function onRowClickHandler(evt){
var clickedTaxLotId = grid.getItem(evt.rowIndex).PARCELID;
var selectedTaxLot;
dojo.forEach(map.graphics.graphics,function(graphic){
if((graphic.attributes) && graphic.attributes.PARCELID === clickedTaxLotId){
selectedTaxLot = graphic;
return;
}
});
var taxLotExtent = selectedTaxLot.geometry.getExtent();
map.setExtent(taxLotExtent);
}
and my HTML is:
<div id ="datagrid" data-dojo-type="dijit.layout.AccordionPane" splitter="true" region="bottom"
style="width:100%; height:125px;">
<table data-dojo-type="dojox.grid.DataGrid" data-dojo-id="grid" id="grid" data-dojo-props="rowsPerPage:'5', rowSelector:'20px'">
<thead>
<tr>
<th field="Parcel Identification Number" width="10%">
Parcel ID
</th>
<th field="Assessing Neighbornood Code" width ="20%">
Neighborhood Code
</th>
<th field="Property Class Code" width="10%">
Property Class
</th>
<th field="Site Address" width="100%">
Address
</th>
</tr>
</thead>
</table>
</div>
This is my best guess at what to add:
<tr>
<td align="right">
<div class="divOk" onclick="dijit.byId('tocDiv').hide();">
OK</div>
</td>
</tr>
I wound up creating a work around for what I want by creating a new column and putting a close icon within the header. I connected it to an function so that when I click it, the grid closes and the map resizes:
function closeGrid() {
esri.hide(datagrid);
dojo.style("map", {"height": "100%"});
}
HTML
<th field="" width="2%"> <div class="GridCloseIcon" title="Close Grid" onclick="closeGrid();"></div>
How about this?
(assuming the OK line actually appears)
HTML
<tr>
<td align="right">
<div class="divOk" onclick="hideGrid();">OK</div>
</td>
</tr>
JS
function hideGrid() {
var widget = dijit.byId('datagrid');
dojo.fadeOut({
node: widget.domNode
}).play();
dojo.style(widget.domNode, 'display', 'none');
}