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?
Related
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');
});
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> -->
[https://i.stack.imgur.com/yKOOF.png]I have to click one of options from left widget (See the Image1.PNG) will display single row as shown in ( See the [https://i.stack.imgur.com/hBNTN.png]Image.PNG) and then mousehover on each and every value and have to capture the tooltip for each values of that particular row..
xpath for the left and right widgets are:
#FindBy(xpath="//*[#id='tabZoneId21']/div/div/div/div[1]/div[5]/div[1]/canvas")
WebElement wbcanvasWidgetLeft;
#FindBy(xpath="//*[#id=\"view5159778620503418402_17231458509407196328\"]/div[1]/div[2]/canvas[2]")
WebElement wbcanvasWidgetRight;
And when I mouse hover on each and every value the following code gets highlights and only the value of ‘left’ gets change otherwise its static for all options.
[![<div class = “ tab-tooltip tab-widget tab-tooltipAR” style=”user-select: none; -webkit-tap-highlight-color: transparent; top: 1px; **left:119px**;”>… </div>
<div class=”tab-tooltipContainer”>
<div class =”tab-tooltipContent” wairole=”alert” style>
<div class=”tab-ubertip tab-widget” style=”min-width: 368px;”>.
<div class =”tab-ubertipContent”>
<div class=”tab-ubertipTooltip”>
<span style =”white-space:pre-wrap;tab-size:10;-moz-tab-size:10”>
<div style=”text-align:left;”>
<span style=””>Health Group </span>
</div>
<table style=”vertical-align:top;padding:0px” cellspacing=”0”>
<tbody>
<tr>
<td style =”white-space:pre”>
span style=”font-family” >97</span>
</td>
<td >
<span style=”font-” >Minimum</span>
</td>][1]][1]
Only the value of ‘left’ gets change for each options with some specific margin.
I have tried with following code which mousehover either 87.7% or 30.2% and displays the tooltip. I am not able mousehover on the first option that is 19.9% and so on in continuous manner.
public void sikuli() throws FindFailed, Exception {
driver.switchTo().frame(driver.findElement(By.cssSelector("iframe[title='data visualization']")));
try{
//Captured image of first option(Health) and clicked on in it
Screen s = new Screen();
Pattern target = new Pattern("Health.PNG");
s.wait(target,20);
s.mouseMove(target);
s.click();
Actions act = new Actions(driver);
act.moveToElement(wbcanvasWidgetLeft).moveByOffset(-50,0).moveToElement(wbcanvasWidgetRight).build().perform();
//Capturing Tooltip
System.out.println(driver.findElement(By.xpath("//div[#class='tab-ubertipTooltip']/span/div[3]/span[1]")).getText());
System.out.println(driver.findElement(By.xpath("//div[#class='tab-ubertipTooltip']/span/div[4]/span")).getText());
}
catch(Exception e)
{
e.printStackTrace();
}
driver.switchTo().defaultContent();
}
Can I use javascript executor with help of style attribute where I set the margin values for ‘left’ but i don't know how to set margin for style attribute while writing xpath.
Any help will be appreciated.
I am using the "Survey Link" template to create a project on Mechanical Turk.
I am running an A/B test. I would like to direct 50% of workers to one link, and 50% to another link.
How do I do this?
From the "Design Layout" page, click on "Source". This will let you edit the html/javascript/css for the survey.
You'll find a <table> element with a <tbody> element. Change the <tbody> element to this:
<tbody>
<tr class="survey-one">
<td><label>Survey link:</label></td>
<td><a class="dont-break-out" href="http://link-to-survey-1">http://link-to-survey-1</a></td>
</tr>
<tr class="survey-two">
<td><label>Survey link:</label></td>
<td><a class="dont-break-out" href="http://link-to-survey-2">http://link-to-survey-2</a></td>
</tr>
</tbody>
This simply adds another row to the table for the link for your second survey. Note the link-to-survey-1 and link-to-survey-2 that you'll need to replace with your own links.
A bit lower in the file, you'll see the <style> element. Add this to it:
.survey-hidden {
display: none;
}
And a bit lower, you'll see a <script> element. At the bottom of it, right before the });, add the following javascript:
var surveyToHide = (Math.random() >= 0.5) ? '.survey-one' : '.survey-two';
$(surveyToHide).addClass('survey-hidden');
This randomly picks one of your suveys, and makes it hidden, so that the worker sees only one.
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');
}