Rails + Multiple DataTables + UI nested accordion - ruby-on-rails-3

I'm using multiple similar dataTables within a nested UI accordion. While I've had no problem initializing multiple dataTables using the class-level selector, I'm having a problem getting the header and footer of any given table to align correctly.
I assume this is the same problem as a dataTable in a tab: the table (or header) needs to be redrawn once the accordion pane is displayed.
With initialization of a single table, or id-based initialization, I've had no problem using fnDraw or fnAdjustColumnSizing in a function to redraw a table on display. However, using mass-initialization, this approach doesn't work, because the specific displayed table can't be easily targeted.
I've tried to find a way of targeting only the currently displayed table for redraw, but haven't been successful.
Has anyone else dealt with this issue successfully? Thanks for any ideas....

I'm sure this is super-hacky, but the only way I could set it up so I could create a dynamic, multi-level accordion with a dataTable nested within each, was to actually nest the dataTable initialization within the accordion activation (at the level of the table), then mark the table div as initialized so it could be re-opened. Here's my js code:
$(document).ready(function(){
$(function() {
$('.accordion.second-level').bind('accordionactivate', function (event, ui) {
if (ui.newPanel.length) {
thisPanel = ('#'+ ui.newPanel.attr('id'));
if ($(thisPanel).hasClass('not_activated')) {
$(thisPanel + ' .dataTables_types').dataTable({
"bAutoWidth": false,
"bPaginate": false,
"bScrollCollapse": true,
"sScrollY": "295px",
"aaSorting": [[ 1, "desc" ]],
"sDom": "<'row'<'span10'f>>t<'row'<'span10'i>>",
"aoColumns": [
{ "bSortable": false },
null,
null,
{ "iDataSort": 4 },
{'bVisible': false},
{'bVisible': false},
null
],
"fnFooterCallback": function ( nRow, aaData, iStart, iEnd, aiDisplay ) {
/* Calculate the total transactions on this page */
var total = 0;
for ( var i=iStart ; i<iEnd ; i++ )
{
total += aaData[ aiDisplay[i] ][5]* 1;
}
var nCells = nRow.getElementsByTagName('th');
nCells[1].innerHTML = total;
$(nCells[1]).formatCurrency({negativeFormat:'%s-%n'});
}
});
$(thisPanel).removeClass('not_activated');
}
}
});
});
});
I'd still love to know if there's a better/more efficient way to do this, but this does work.

Related

Dynamically update plugin view in ckeditor 5

I'm using ckEditor 5.
My aim is to create a simple search functionality to perform some ajax calls, allow the user to select from a result list and act accordingly (inserting link, or image, or media...).
The problem is that I want to dynamically update the plugin view. Something similar to this: https://github.com/ckeditor/ckeditor5/issues/520, but I'm using a dropdown in the toolbar (I started from the EmbedMedia plugin and didn't care too much about design for now).
I asked the same question on their git (https://github.com/ckeditor/ckeditor5/issues/1681)
My template is like:
this.setTemplate( {
tag: 'form',
attributes: {
class: [
'ck',
'ck-results-form'
],
tabindex: '-1'
},
children: [
this.searchInputView,
this.searchButtonView,
{
tag: 'div',
attributes: {
class: [ 'ck-result-grid' ]
},
children: this.items
},
this.saveButtonView,
this.cancelButtonView,
]
} );
// updateList method is like this:
updateList( valuesArray ) {
console.log(this.items);
this.items = new Array();
console.log(this.items);
for (let i = 0; i < valuesArray.length && i < 20; i++) {
const urlView = new TableSizeGridBoxView(i, valuesArray[i]);
urlView.on('select-url', () => {
this._selectedUrl = valuesArray[i];
});
this.items.push( urlView );
}
console.log(this.items);
//do something here to force refresh or render the section
}
I'm able to get
My expected result, after the search, is to get
and finally select the result.
Currently I can see the object correctly initialized and updated by doing console.log, but the view doesn't update... it stays blank as in the first image (that's why I think there must be something I should be able to put where I wrote //do something here to force refresh or render the section).
Furtermore I can tell that TableSizeGridBoxView is working properly because I'm able to display arbitrary values if I call the for loop in the initialization of the view.

dc.js dataTable Conditional formatting using jquery dataTable

I have a dashboard which is built using dc.js and i'm using the chart types dc.rowChart and dc.dataTables.
Working Scenario with without conditional formatting:
dc.rowChart - displays Top 50 Customers
dc.dataTable - displays all the fields required and filters the data based on the rowChart.
Working Scenario with conditional Formatting (on datatable rows)
In my HTML, i'm calling the jquery plugin for DataTable (for conditioanl formatting) and here is the code below:
<script>
$(document).ready(function() {
$("#Table").DataTable( {
/*
fnRowCallback: function(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
if ($(nRow).find('td:eq(7)').text()<'0') {
$(nRow).find('td:eq(7)').addClass('color');
}
}
*/
columns : [
{ title : "Customer Name" },
{ title : "YoY Rank Change" ,
render: function ( data, type, row ) {
if (data > '0') {
return '<p class="positive">'+data+'</p>';
} else {
return '<p class="negative">'+data+'</p>';
} } },
{ title : "Jan'19 Qty" },
{ title : "Dec'18 Qty" },
{ title : "Nov'18 Qty" },
{ title : "Oct'18 Qty" },
{ title : "Sep'18 Qty" },
{ title : "Aug'18 Qty" }
]
} );
} );
$.extend( true, $.fn.dataTable.defaults, {
"searching": true,
"ordering": false,
"paging": false,
"info": false,
} );
</script>
CSS:
.negative {
background-color:rgba(255,0,0,1.00);
color: #fff;
text-align: center;
}
.positive {
background-color:rgba(50,205,50,1.00);
color: #fff;
text-align: center;
}
ISSUE HERE
When i render the page first time, everything with the datatable with conditional formatting works fine
But when i click on Row Chart to filter datatable based on Customer's, Conditional formatting is gone...
Any help is much appreciated to fix this.
I have tried almost all the stack answers but i'm not able to achieve it.
references used below:
1. How to color code rows in a table dc.datatable?
2. How do I apply conditional formatting using datatables.js?
3. Color code a data table in dc.js
4. How to color code rows in a table dc.datatable? ( This is opted out as i dont want to color code entire row)
#Gordon my survivor at all times.. Looking for your inputs please!!
I see that you are still on dc.js 2.0, so I didn't attempt to port this to dc.datatables.js or dc-tableview. I still think that would be more maintainable.
As I noted in the comments, $.DataTable is a one-way transformation: once you have done this, there is no way to update the table, because dc.dataTable doesn't recognize the DOM structure anymore, and DataTable doesn't have a way to reinitialize.
There might be some smart way to get DataTables to update the data (and this is what the libraries do). It's also madly inefficient to first build a table and then construct a DataTable using the DOM as a data source.
But whatever, let's just get this working by building the DataTable from scratch every time the dc.dataTable is drawn.
The way to do this is to listen for the table's pretransition event, remember if we've already initialized DataTable, and if we have, destroy the old instance:
var dt = null;
table.on('pretransition', function() {
if(dt)
dt.destroy();
dt = $("#dc-data-grid").DataTable( {
// as before
} );
});
Fork of your fiddle. I had to fix a few other things, but I won't go into the details.

Datatables Enable/disable column sorting when click on table header span

following some suggestions on related questions, I was able to unbind and bind again the default column sorting event.
But ended in a strange sorting behavior, when there are one or more hidden columns.
Desired behaviour:
I have a span inside a TH of a Databales column, that has to open a bootstrap-modal with remote url. but I don't want the sorting default event to be triggered, so onClick of the span I have placed this:$('th').off('click.DT');
then I have this handler that fires the modal , and then binds the order listening again with no problem: `
$('body').on('click', '[data-toggle="modal"]', function(){
$($(this).data("target")+' .modal-body').load($(this).data("remote"));
table.columns().every( function (i) {
if(table.columns().visible()[i]){
table.order.listener( $('#Testata th:eq('+i+')'), i);
}
});
});`
the problem arises when there are hidden columns:
with one hidden column i.e.: `
'columnDefs': [
{
"targets": [0],
"visible": false
}]`
the order listener works on all columns but the sorting is wrong.
with more then one hidden columns i.e.: `
'columnDefs': [
{
"targets": [0],
"visible": false
},
{
"targets": [3],
"visible": false
}
]`
the order listener works NOT on all columns and the sorting is wrong.
Here a fiddle to simulate the scenario please click on the (i) span on the first column.
thanks a lot.
You need to assign a different running number that counts only the visible columns:
$('body').on('click', '[data-toggle="modal"]', function(){
$($(this).data("target")+' .modal-body').load($(this).data("remote"));
var elIdx = 0;
table.columns(':visible').every( function (i) {
table.order.listener( $('#Testata th:eq('+elIdx+')'), i);
elIdx++;
});
});
jsFiddle

Integrate Bootstrap typeahead js with Bootstrap Datatable

I am using bootstrap data-tables Datatables and bootstrap-taginput with typehead.js. I am new with bootstrap data-tables.
Here is the layout of my bootstrap data-tables Example and please consider Bootstrap tagging input box on top.
I want to search data-tables records with bootstrap tagging elements. but somehow i am unable to search with bootstrap tagging.
Thanks in advance.
If you start out with an empty array of the data you've got on your table you could do something clever by replacing the built in search box. In the example I'm linking to I don't care about one of the columns and the other columns need a little formatting:
var words = [];
var table = $('#example').DataTable({
"columns": [
null, {
"render": function(data, type, row) {
~words.indexOf(data) || words.push(data);
return data;
}
}, {
"render": function(data, type, row) {
var d = data.replace(/\, /g, " ");
~words.indexOf(d) || words.push(d);
return data.split(", ").join("<br/>");
}
}
],
"initComplete": function() {
var searchBox = $("#example_wrapper").find("input[type='search']");
var searchBoxHolder = searchBox.parent();
searchBox.empty().remove();
searchBoxHolder.append($("<input/>", {
"type": "text"
}).typeahead({
source: words,
afterSelect: function(word) {
table.search(word).draw();
}
}).on("keyup", function(x) {
if (words.indexOf($(x.target).val()) === -1) {
table.search($(x.target).val()).draw();
}
}));
}
});
Basically what we're doing here is creating a blank array of search terms then iterating over each second and third cell and adding the term to the array if it doesn't exist. In the case of the third cell I need to clear some formatting (extra comma). Then we get the original search box and it's parent. Remove the original and append the new one to the parent. We then set it up as a typeahead with the list of search terms. We need to make sure it still acts like the original so we add the keyup function. I hope that makes sense.
Working example is here, hope that helps.

dgrid inside ContentPane - Scroll error

I have a problem with dgrid.... I have an AccordionContainer, and in each ContentPane of it,
I place a dgrid. The problems with the dgrid are:
1- Error with scroll: when scrolling down, in certain moment the scroll "skips" and jumps into the end and there's no way to scroll up and show the first records.
(I have seen in Firebug the error TypeError: grid._rows is null when the scroll fails).
2- Trying to change a value: sounds like no dgrid-datachange event is emitted,
no way to capture the event after editing a value.
I think these errors has to do with having dgrid inside layouts (dgrid inside ContentPane, inside AccordionContainer). I also included the DijitRegistry extension but even with this extensions I can't get
rid of this errors.
I have prepared this fiddle which reproduces the errors:
https://jsfiddle.net/9ax3q9jw/5/
Code:
var grid = new (declare([OnDemandGrid, DijitRegistry,Selection, Selector, Editor]))({
collection: tsStore,
selectionMode: 'none',
columns:
[
{id: 'timestamp', label:'Timestamp', formatter: function (value,rowIndex) {
return value[0];
}},
{id: 'value', label: 'Value',
get: function(value){
return value[1];
},
editor: "dijit/form/TextBox"
}
],
showHeader: true
});
grid.startup();
grid.on('dgrid-datachange',function(event){
alert('Change!');
console.log('Change: ' + JSON.stringify(event));
});
//Add Grid and TextArea to AccordionContainer.
var cp = new ContentPane({
title: tsStore.name,
content: grid
},"accordionContainer");
Any help will be appreciated,
Thanks,
Angel.
There are a couple of issues with this example that may be causing you problems.
Data
The store used in the fiddle is being created with an array of arrays, but stores are intended to work with arrays of objects. This is the root of the scrolling issue you're seeing. One property in each object should uniquely identify that object (the 'id' field). Without entry IDs, the grid can't properly keep track of the entries in your data set. The data array can easily be converted to an object array with each entry having timestamp and value properties, and the store can use timestamp as its ID property (the property it uses to uniquely identify each record).
var records = [];
var data = _globalData[0].data;
var item;
for (var i = 0; i < data.length; i++) {
item = data[i];
records.push({
timestamp: item[0],
value: item[1]
});
}
var tsStore = new declare([Memory, Trackable])({
data: records,
idProperty: 'timestamp',
name: 'Temperature'
});
_t._createTimeSeriesGrids(tsStore);
Setting up the store this way also allows the grid column definitions to be simplified. Using field names instead of IDs will allow the grid to call formatter functions with the corresponding field value for each row object.
columns: [{
field: 'timestamp',
label: 'Timestamp',
formatter: function (value) {
return value;
}
}, {
field: 'value',
label: 'Value',
formatter: function (value) {
return value;
},
editor: "dijit/form/TextBox"
}],
Loading
The fiddle is using declarative widgets and Dojo's automatic parsing functionality to build the page. In this situation the loader callback does not wait for the parser to complete before executing, so the widgets may not have been instantiated when the callback runs.
There are two ways to handle this: dojo/ready or explicit use of the parser.
parseOnLoad: true,
deps: [
...
dojo/ready,
dojo/domReady!
],
callback: function (..., ready) {
ready(function () {
var _t = this;
var _globalData = [];
...
});
}
or
parseOnLoad: false,
deps: [
...
dojo/parser,
dojo/domReady!
],
callback: function (..., parser) {
parser.parse().then(function () {
var _t = this;
var _globalData = [];
...
});
}
Layout
When adding widgets to containers, use Dijit's methods, like addChild and set('content', ...). These typically perform actions other than just adding a widget to the DOM, like starting up child widgets.
var cp = new ContentPane({
title: tsStore.name,
content: grid
});
registry.byId('accordionContainer').addChild(cp);
instead of
var cp = new ContentPane({
title: tsStore.name,
content: grid
}, "accordionContainer");
In the example code a ContentPane isn't even needed since the dgrid inherits from DijitRegistry -- it can be added directly as a child of the AccordionContainer.
This will also call the grid's startup method, so the explicit call in the code isn't needed.
registry.byId('accordionContainer').addChild(grid);
It also often necessary to re-layout the grid's container once the grid has been initially rendered to ensure it's properly sized.
var handle = grid.on('dgrid-refresh-complete', function () {
registry.byId('accordionContainer').resize();
// only need to do this the first time
handle.remove();
});