How can I use generic formatter on multiple SlickGrid s? - javascript

I am developing a web app using SlickGrid.
Our application has many grids in different tabs/pages and for that reason I am wondering if I can refactor some code so that I am not writing the same functions over and over for seperate grids.
An example:
I need a custom Formatter since we have multiple tree grids (the formatter to implement the tree structure is identical for each grid.):
function PercentCompleteFormatter(row, cell, value, columnDef, dataContext)
Given that I cannot pass the grid or a dataview as an arguement (assuming the signature above must be used for all custom formatter.), I basically have to have the same formatter code inside each code block where I am creating the grid.
Is there a way I can create one "generic" formatter and apply it to ALL grids?
The same question applies to things like sorting, filtering, etc... but I hope the above explaination covers what I'm trying to ask.
Thanks!

You can use jQuery's .proxy() helper (or similar) to bind a function to a particular context.
For example:
function MyFormatter(row, cell, value) {
var grid = this; // the grid will be the executing scope
// ...
}
var myFormatterForGridA = $.proxy(MyFormatter, gridA);
var myFormatterForGridB = $.proxy(MyFormatter, gridB);

Related

AG Data Grid table: generate a Vega-Lite chart that updates automatically

I would like to use Ag Data Grid filtered data to generate plots in Vega-Lite that update automatically whenever the filter(s) are changed. I would prefer to have the implementation in an observablehq notebook. Here is a section on how to access the table data in Ag Grid documentation. I created an observablehq notebook where the chart is updated using a button. There are two issues with this implementation:
The chart is generated only after the button is clicked.
I would prefer the chart update to be automatic without the need to click a button.
Thanks for linking to the notebook! It appears that the angular table does update, but it appends to the element and gets drawn behind the code cells. This is what it looks like in my browser when I move the slider:
The problem with components like this that manipulate the DOM is that they work against Observable's way of managing the DOM. Even if the component were to update correctly, it would probably still not resize the way you'd expect.
Observable is already reactive at its core, which is something angular (and other frameworks like React) was built to add to JavaScript. Using Observable's built-in reactivity will be much easier in the long run than trying to make two different reactivity models work with each other.
You can make the AG Grid table an Observable “view” so that you can both (1) see the table and (2) refer to its value in other cells, which will re-run when you filter the table. Once you do that, it'll work naturally with anything else you want to do in the notebook. Here's a working example with Observable Plot, and here's the same example with Vega-Lite.
Assuming you've loaded AgGrid and have gridOptions in a different cell, you can wrap AgGrid as an Observable view like this:
viewof table = {
const node = htl.html`<div style="height:320px;" class="ag-theme-alpine"></div>`;
new AgGrid.Grid(node, gridOptions);
gridOptions.api.addEventListener("modelUpdated", update) // set value after filter
gridOptions.api.sizeColumnsToFit();
update(); // set initial value
function update() { // for Observable dataflow
let value = [];
gridOptions.api.forEachNodeAfterFilter(d => value.push(d.data));
node.value = value;
node.dispatchEvent(new Event("input"));
}
return node;
}
A few notes on how this is different from your version (as of when I saw it):
I put the HTML and the AgGrid initialization in the same cell, so that AgGrid has an object reference to the node and if you re-run the cell it all gets cleaned up and recreated as a whole.
I listen for when the grid rows change with gridOptions.api.addEventListener("modelUpdated", update).
In that update function, I do the same iteration over the rows that you were doing to build an array, but then I set it as the value of the node, and dispatch an input event from that node. That's what Observable looks for to tell when a view has changed its value and other cells should re-run.
I name the cell viewof table. You might've seen this pattern with sliders and other inputs on Observable. The viewof keyword means that you get the DOM node rendered, but you can also refer to its value with just table in other cells.
Thanks for the question; I’ve been meaning to check out AG Grid for a while!

How to get a dataFiltered-Callback for a specific Column Header Filters?

as far as I understand there is only the callback dataFiltered, which is used for the whole table. It is triggered by all filters indifferently.
Is it possible to get a callback for a specific single header filter?
So that I can call a function as soon as a certain header filter becomes active?
I imagine it to be something like this:
{title:"Name", field:"name", headerFilter:true, headerdataFiltered:function()}
Is there possibly a workaround?
Thanks a lot!
(I would be especially grateful for non-jquery solutions)
Thanks also for this realy wonderful tool Tabulator.
Thanks for your kind words, it is always great to hear that Tabulator is appreciated.
The reason it is called when any filter is applied is because multiple filters can be applied at once, with Complex Filtering a complex and/or filter set can be applied so it would be hard to isolate down to specific columns in all cases.
The dataFiltered callback does get passed a list of all currently active filters so you can see if your affected column is in that:
var table = new Tabulator("#example-table", {
dataFiltering:function(filters){
//filters - array of filters currently applied
},
});
If you need to see if the column has just been filtered you can store a copy of the previous value of this object outside the callback and then compare the old and new values on the next call.
The other option would be to use a custom editor in the header filter then you could manually decide when the success function is called that initiates the filter and then reference an external function from there

Ext js 5.0.1 column custom sorting

I am new to extjs framework and looking for a way to add a custom sorting function to a column in a panel. I went through some of the post, and it seems that this functionality has been changed a few times over time.
In 5.0.1 documentation I found sortType configuration that can be used to convert the data to a comparable value.
But in my case, converting all the data to a value and then sorting could be a time consuming process and I was looking to use a function like the one used in doSort configuration earlier similar to this example; by basically configuring a function like this:
function customSorter(state){
var ds = this.up('grid').getStore();
var field = this.getSortParam();
ds.sort({
property: field,
direction: state,
sorterFn: function(v1,v2){
//some custom logic
}
});
}
EDIT 1: I am looking to use this function for only one column, the other columns are standard data types and sorting works fine by default for those.
Any ideas how to do this in 5.0.1?
Thanks in advance..
You can pass an array of Ext.util.Sorter to the sort method of your store. The Ext.util.Sorter class has an sorterFn config.
references:
https://docs.sencha.com/extjs/5.0.1/api/Ext.util.Sorter.html
https://docs.sencha.com/extjs/5.0.1/api/Ext.data.Store.html#method-sort
If you want to have a custom sort for a specific colum you can use the sortType config on the field corresponding to the column, see https://docs.sencha.com/extjs/5.0.1/api/Ext.data.field.Field.html#cfg-sortType

Get Row Number with Handsontable

Super noob question here. I have an array of row indexes that I would like to use to change the color of my Handsontable rows. I figure HOT would provide a method to retrieve the tr element of a table with something like hot.getRow(5), but it doesn't seem to exist.
So in a nutshell I'm trying to do this
var rowIds = []
$.each(rowIds , function (i, element) {
var row = hot.getRow(i);
$(row).closest('tr').css('color','green');
});
I've found I can use getCell() method which accepts a row and column # along with a boolean, but using this would require extra code for something that should be as simple as passing a single argument. Is there a method I'm overlooking or is this the only way?
Here's the thing with how HOT works: it is a JS object which renders a stateless DOM table. This means you should never EVER try to manually modify the HTML of your table. Even if you did want to do that, as soon as you make a change to those green cells, they would get re-rendered, not green.
Instead, you want to use the readily accessible 'custom renderers' that are associated with each column or cell, depending on how you define them. These are applied just like the data attribute in the columns or cells definition. They are functions and here's an example:
function greenCellRenderer(instance, td, row, col, prop, value, cellProperties) {
Handsontable.renderers.TextRenderer.apply(this, arguments);
td.style.color = 'green';
}
You should read up on the full documentation to understand the full power of the renderer but it's pretty clear from the arguments it takes what you can do. One thing you would be able to do is apply the green color you're hoping for. Of course to selectively do this you would either apply the renderer to specific cells, or put a conditional inside this general renderer using the row and col arguments to your advantage.
Hope that helps!

Sorting a DataTable using custom function does not work

I am working with DataTables plug-in in JavaScript.
Usually, if I need to update a cell value, I use the cell().data(set) method followed by .draw().
However, I do not want to use this way because my table contains heavy DOM object. So, when I need to update a cell, I just call some jQuery like $("#cell").attr("myattr", 50) for example, and then I managed to never have to use draw(). This prevents the object to be rebuilt each time, but unfortunately it also means that the DataTable is not aware of these changes (cell().data() returns the unchanged object).
This is a problem when I want my table to be sorted. In fact, the sorting is performed on the data that the datatable known, data which is not changed.
So I thought I could use the columns.render option, implementing a function like this:
function(data, type, row, meta) {
if (type === "sort") {
return $("#cell").attr("myattr");
}
return data;
}
This does not work and I think this is because of the fact that DataTable caches the data. So, as I never update cells data, cache never need to be updated, and sorting is done using this cache, which does not correspond the cell myattr attribute.
I am looking for a workaround which can allow me to sort a DataTable even if cells values are not changed internally but from outside.
Play with this JSFiddle, clicking the "CHANGE VALUES" button and trying to sort the column, you can see that the values are not correctly ordered.
There are couple solutions:
SOLUTION #1
Use cell().invalidate() API method to invalidate data in cache as shown below:
$('#example').DataTable().cell($("#a").closest('td')).invalidate('dom').draw(false);
DEMO
See this jsFiddle for code and demonstration.
SOLUTION #2
You can use columns.orderDataType to specify name of custom ordering plug-in, see Custom data source sorting. These plug-ins can access live DOM content.
Please note that there are no plug-ins built into DataTables, they must be added separately.
You can use dom-text plug-in as a base and write your own function to access the data for sorting.
DEMO
See this jsFiddle for code and demonstration.

Categories