Wanna disable the column (row no:) from sorting usage by Tabulator js plugin - jquery-ui-sortable

How can I make all columns on a Tabulator table auto sort except the first column
I have tried sortable:false & headerSort:false.
img(1) Initial table
img(2) Sorting table at Name: column.
(Target : Remaining the No: value from 1 to 6 by ascending order even Name: order change.)
Could you please help me to find a solution.
Thanks.

As per;
https://github.com/olifolkerd/tabulator/issues/861
"You need to set the headerSort property in the column definition object for the column you want to not be sortable, not on the table as a whole. the sortable property you are currently using in your column definition was removed in version 3.0"
$("#mytable").tabulator({
height:205, // Set height of table, this enables the Virtual DOM and improves render speed
//layout:"fitColumns", // Fit columns to width of table (optional)
resizableColumns:false, // Disable column resize
responsiveLayout:true, // Enable responsive layouts
placeholder:"No Data Available", // Display message to user on empty table
initialSort:[ // Define the sort order:
{column:"altitude", dir:"asc"}, // 1'st // THIS IS WHAT YOU'RE LOOKING FOR I ASSUMEN
],
columns:[
{title:"Flight", field:"flight", headerSort:false, responsive:0, align:"left"}, // , width:250},
{title:"CallSig", field:"callsign", headerSort:false, responsive:3},
...
Further reading: http://tabulator.info/docs/3.3#sorting
EDIT: You can set sorting programmatically;
$("#example-table").tabulator("setSort", "age", "asc");
Hope this helps.

Related

Format Column Header on pivot table as date in ag-grid

I am using a valueFormatter for my date columns in ag-grid (react) that looks like this:
columnTypes: {
"dateColumn": {
filter: 'agDateColumnFilter',
enableRowGroup: true,
valueFormatter: Blotter.formatDate,
enablePivot: true,
enableValue: true
}
}
where Blotter.formatDate is a simple formatter that outputs the date in the user's preferred format. However, a common requirement in my application is to build pivot tables using a date series so the date column ends up in the "Column Labels" section of the pivot definitions. When I do this, the date column header shows the full, unformatted date and is also not sorted in any particular order. How can I make it so that the column label formats the dates in a reasonable way and have them sorted incrementing from left to right?
Here's what I'm seeing:
The dates across the top are from the "Position Date" column, which renders like this when pivot is not turned on:
Thankyou,
Troy
I was stuck with the same problem. I finally found the solution.
You must set the keyCreator on you column definition
As Olivier mentioned you can use the keyCreator property for your purpose.
But be aware when you use it together with valueFormatter, it causes a strange behaviour in your Pivot.
Here a link to the official documentation where you can find out more
https://www.ag-grid.com/angular-grid/column-properties/
processSecondaryColDef
"This is a callback that gets called on each group definition":
processSecondaryColGroupDef
.
Using the method above you can resolve the problem.
I fixed the same issue in my project.
From the link:
// This is a callback that gets called on each column definition
processSecondaryColDef: function (colDef) {
colDef.headerName = colDef.headerName.toUpperCase();
},
processSecondaryColGroupDef: function (colGroupDef) {
if (colGroupDef.pivotKeys[0] === '2002') {
colGroupDef.headerClass = 'color-background';
}
colGroupDef.headerName = 'Year ' + colGroupDef.headerName;
},
};

AgGridReact component not updating when autoGroupColumnDef changes

I'm using ag-Grid with React to test their enterprise row grouping feature. I want to change the row grouping column name during runtime, but I haven't been able to do this.
When I make changes to AgGridReact's columnDefs prop, the changes are reflected in the table. But changes to the autoGroupColumnDef prop aren't rendered, even though the debug logs show that the change was detected. Here's an example in TypeScript (using React hooks for state):
import React, { FC, useState } from 'react';
import 'ag-grid-enterprise';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-balham.css';
const AgGridTest: FC = () => {
const rowData = [
{ col1: 'a', col2: 0, col3: 0 },
{ col1: 'b', col2: 1, col3: 1 },
{ col1: 'c', col2: 2, col3: 0 },
{ col1: 'd', col2: 3, col3: 1 },
{ col1: 'a', col2: 4, col3: 0 },
{ col1: 'b', col2: 5, col3: 1 },
{ col1: 'c', col2: 6, col3: 0 },
{ col1: 'd', col2: 7, col3: 1 },
];
const [columnDefs, setColumnDefs] = useState([
{ headerName: 'Column 1', field: 'col1', rowGroup: true }, // initial group column
{ headerName: 'Column 2', field: 'col2', rowGroup: false },
{ headerName: 'Column 3', field: 'col3', rowGroup: false },
]);
const [autoGroupColumnDef, setAutoGroupColumnDef] = useState(
{headerName: 'col1 Initial'} // auto group column name is 'col1 Initial' to start
);
const groupByColumn = (field: string): void => {
// this successfully changes the grouping column...
setColumnDefs(
prevColumnDefs => prevColumnDefs.map(
colDef => colDef.field === field ?
{...colDef, rowGroup: true} :
{...colDef, rowGroup: false}
)
);
// ...but this won't change the auto group column name!
setAutoGroupColumnDef({
headerName: `${field} Group Column`,
});
}
return (
<div className="ag-theme-balham" style={{ height: '300px' }}>
<button onClick={() => groupByColumn('col1')}>Group by Column 1</button>
<button onClick={() => groupByColumn('col2')}>Group by Column 2</button>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
autoGroupColumnDef={autoGroupColumnDef}
debug // enable debug logs
/>
</div>
);
}
const App: React.FC = () => <AgGridTest />
export default App;
I tried calling the grid API's api.refreshHeader but that didn't work either:
const AgGridTest: FC = () => {
// ...
// store the api in an instance variable
// when the on ready event makes it available
const api = useRef<GridApi>();
const onGridReady = (params: GridReadyEvent) => {
api.current = params.api;
}
const groupByColumn = (field: string): void => {
// ... re-assign the grouping cols ...
}
useEffect(() => {
// run this after grouping changes have been rendered
gridApi.current && gridApi.current.refreshHeader(); // doesn't work
});
return (
<div>
<AgGridReact
onGridReady={onGridReady}
// ...
/>
</div>
);
}
I tried looking for an API function to set the autoColumnGroupDef but I couldn't find one. The documentation only mentions setting properties through gridOptions. The API has a function for updating regular column definitions: api.setColumnDefs. This is what AgGridReact calls when the columnDefs prop changes (relevant code snippets here and here). But when the autoGroupColumnDef property is changed, AgGridReact simply overwrites the autoGroupColumnDef property in the gridOptions object (relevant code snippet). There doesn't seem to be any associated setter function.
There doesn't even seem to be a way to get at the auto group column objects. columnApi.getAllColumns/getColumnGroup only return regular columns. The auto group column list is kept separately in a private instance variable in columnController (relevant code snippet), which has a public getPrimaryAndSecondaryAndAutoColumns accessor exposed, except that we can't access the columnController API.
Any ideas on how can I modify the auto group column names at runtime? Or do I have to disable them and create my own group columns?
This question was asked here and here but they never received answers (and I don't understand the comment in the second question).
As you are probably aware, ag-grid is pure js, and the React and Angular versions are wrappers around that.
I've been using the Angular version for about a year, and customizing it heavily, and I've found that many of the gridOptions, even though they are bound properties, have no effect after initial instantiation of the grid. I suspect that autoGroupColumnDef is one of these.
So, I would try creating your own column groups, as per the link that you referenced.
If that doesn't work, the (ugly) alternative is to destroy the grid, and then recreate it with the new gridOptions reflecting your new autoGroupColumnDef
One other hard-won piece of advice:
If you use the setColumnDefs API to update the column definitions, it works fine, BUT, if you later want save and restore the grid state, getting the grid state from the API yields column names with "_1" appended to them, and if you set the column state with that, you get an error about the columns not being found. The solution is to set the columnDefs to an empty array first, and then set your actual columnDefs.
#GreyBeardedGeek mentioned that using the setColumnDefs API mutates the column names. This sent me down a rabbit hole which may prove useful to others.
tl;dr
If you want to change column order, width, sort state, filtering, row grouping, or pivoting at runtime through the API (e.g. api.setColumnDefs) instead of only through ag-Grid's UI controls (e.g. allowing the user to resize columns by clicking and dragging), you must:
Specify a unique colId for each column.
Set gridOptions.deltaColumnMode to true.
If you want to also allow the user to modify these properties (e.g. click-n-drag resize), add an explicit handler that watches for these changes and updates the columnDefs accordingly.
I'll now explain why (sort of - some parts are still unclear to me).
If you provide colIds but leave deltaColumnMode false...
I made a plunkr where you can create a new column and update the new column and an existing column's sort order, width, and whether it's a row grouping column. The first thing to note is that the initial width in the columnDefs for column 1 is applied, but clicking "increase width" for either the existing or new column does nothing. Grouping doesn't work either - the cell renderer will change, centering the content, but no grouping will actually be performed.
This is because deltaColumnMode is false by default, and when deltaColumnMode is false, runtime changes to certain properties (which include width and row grouping) are ignored. From the docs:
By default when new columns are loaded into the grid, the following properties are not used:
Column Order
Aggregation Function (colDef.aggFunc)
Width (colDef.width)
Pivot (colDef.pivot or colDef.pivotIndex)
Row Group (colDef.rowGroup or colDef.rowGroupIndex)
Pinned (colDef.pinned)
This is done on purpose to avoid unexpected behaviour for the application user.
For example - suppose the application user rearranges the order of the columns. Then if the application sets new column definitions for the purposes of adding one extra column into the grid, then it would be a bad user experience to reset the order of all the columns.
Similarly, when we create the new column, we place it first in the list of columnDefs, but this order is ignored and it's instead created at the end. This is because column order is one of the properties ignored when deltaColumnMode is false.
The second thing to note is that sort order is preserved even when we make columnDefs updates. Because we provided colIds, ag-Grid knew that when we changed the columnDefs, we were updating existing columns and not creating new ones. ag-Grid preserves internal state like sort order and row grouping when the colIds are the same. From the docs:
Comparison of column definitions is done on 1) object reference comparison and 2) column ID eg colDef.colId. If either the object reference matches, or the column ID matches, then the grid treats the columns as the same column. For example if the grid has a column with ID 'country' and the user sets new columns, one of which also has ID of 'country', then the old country column is kept in place of the new one keeping it's internal state such as width, position, sort and filter.
If you don't provide any colIds and leave deltaColumnMode false...
If you don't provide colIds in the initial columnDefs, ag-Grid will assign them internally:
If the user provides colId in the column definition, then this is used, otherwise the field is used. If both colId and field then colId gets preference. If neither colId or field then numeric is provided. Then finally the ID ensured to be unique by appending '_[n]' where n is the first positive number that allows uniqueness.
Whenever columnDefs change, ag-Grid decides whether the changes are to an existing column or to a new column by checking the colIds (or column object references). From the docs:
If you are updating the columns (not replacing the entire set) then you must either provide column ID's or reuse the column definition object instances. Otherwise the grid will not know that the columns are in fact the same columns.
When we provided colIds, ag-Grid knew we were updating existing columns. But when we don't provide colIds, ag-Grid doesn't know what to do. Let's look at the same plunkr as before but with colIds removed. Now, when we click the button to increase column 1's width, three things happen: 1) column 1's width does increase, but 2) its order shifts so it's now the rightmost column, and 3) if we keep clicking "increase width", we see in the console that column 1's colId was initially undefined, becomes "col1" (the field name) after the first increase, and then alternates between "col1_1" and "col1" on every other increase.
I suspect that this strange behavior is due to the way ag-Grid resolves columnDefs updates when colIds aren't provided. Because no colId is provided, ag-Grid seems to think that we're creating a new column when we update column 1's width. Since ag-Grid thinks this is a new column, the width change is actually applied, even though deltaColumnMode is false (remember that in the previous example with colIds set, the width property was applied when the column was created, just not during runtime). But because deltaColumnMode is false, when we create a new column, its order is ignored - hence, column 1 is placed as the rightmost column. (Though, since the docs say that width/column order should be ignored "when new columns are loaded into the grid", I don't quite know why the initial width is applied but column order is not).
Similar things happen when we group by column 1, but 1) all colIds change for all columns, and 2) the grouping column is moved to be the leftmost column. I suspect the first is because all columns change when grouping is applied, and the second is because the grouping column is moved to the left by default, as when we create a new column and group by it, it'll be moved to the left, too.
You may notice that sometimes after making changes to either column 1 or the new column, you're not able to apply any sorting to them. Remember how ag-Grid alternates between appending and removing a "_1" to the colIds? Since api.setSortModel looks up columns by colIds, every time the colId has a "_1" appended to it, api.setSortModel won't be able to find the column to apply sorting (and will fail silently, apparently). We could fix this by getting the current colIds with columnApi.getAllColumns() and using those instead.
Also, since no colIds are provided, ag-Grid doesn't preserve column state (e.g. sort order) between columnDef changes. If you sort a column and then increase its width or group by it, the sorting will be reset. This is because sorting is attached to the internal state of the column object, but the column objects are destroyed when the columnDefs change.
If you provide colIds and set deltaColumnMode to true...
Here's a plunkr to demonstrate. Now, things work as we expect: runtime changes are applied, the new column is created in the leftmost position, and sort order is preserved between columnDef updates. However, there's a reason that deltaColumnMode is false by default. Again, from the docs (emphasis mine):
This is done on purpose to avoid unexpected behaviour for the application user.
For example - suppose the application user rearranges the order of the columns. Then if the application sets new column definitions for the purposes of adding one extra column into the grid, then it would be a bad user experience to reset the order of all the columns.
Likewise if the user changes an aggregation function, or the width of a column, or whether a column was pinned, all of these changes the user does should not get undone because the application decided to update the column definitions.
To change this behaviour and have column attributes above (order, width, row group etc) take effect each time the application updates the grid columns, then set gridOption.deltaColumnMode=true. The responsibility is then on your application to make sure the provided column definitions are in sync with what is in the grid if you don't want undesired visible changes - eg if the user changes the width of a column, the application should listen to the grid event columnWidthChanged and update the applications column definition with the new width - otherwise the width will reset back to the default after the application updates the column definitions into the grid.
Try dragging column 1 to a different order and then increasing its width. You'll see that its order gets reset to its original order in the columnDefs, just as the docs say. To preserve column order, you need to set a listener for the column drag event and update the columnDefs with the new order - see this plunkr and the onDragStopped handler for an example.
And if you want to allow the user to change aggregation functions, width, pivoting, row grouping, or pinning through the ag-Grid default UI controls, you'll need to add listeners for these changes, too.
I've been tackling this issue for a while, and I finally found a solution (albeit a bit out of the box, but it works)
If the only thing you want to change is the header, you can use dom manipulation. You just have to get the exact element that holds the title that you wish to change. In my case, I wanted to show the list of selected aggregations in the order they were selected, and so I was able to accomplish it via:
aggregateMyColumn() {
this.gridColumnApi.setRowGroupColumns(this.orderedAggregationFields);
if(this.orderedAggregationFields.length > 0) {
const container = document.querySelector("#agGrid");
const matches = container.querySelector("div[col-id='ag-Grid-AutoColumn']");
const final = container.querySelector("span[role='columnheader']");
this.renderer.setProperty(final, 'innerHTML', this.orderedAggregationFields.toString());
}
}
Note: there are reasons to use renderer2 to set properties/change innerhtml (something something security), here are some useful links though:
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
https://www.ninjadevcorner.com/2019/04/dom-manipulation-using-angular-renderer2.html

How to select a row in kendogrid after filtering

I have a kendogrid. What I do is first filter it, which works fine.
After having it filtered, I want to select a specific row. I am sure I have the row in the result of the filter.
Example:
data = id=a1, id=a2, id=a3, id=a4, id=a5, id=a6
filter result:
id=a2, id=a4, id=a6
I would like to select the row a4.
First of all loop through the Grid's data which is currently displayed (i.e.
var arrayOfModels = $('#GridName').data().kendoGrid.dataSource.view();
next add the k-state-selected class to the row you want to make it selected
$('#GridName tbody [data-uid='+model.uid+']').addClass('.k-state-selected')
where model is the record from the arrayOfModels above which you need

One to Many equivalent in Cassandra and data model optimization

I am modeling my database in Cassandra, coming from RDBMS. I want to know how can I create a one-to-many relationship which is embedded in the same Column Name and model my table to fit the following query needs.
For example:
Boxes:{
23442:{
belongs_to_user: user1,
box_title: 'the box title',
items:{
1: {
name: 'itemname1',
size: 44
},
2: {
name: 'itemname2',
size: 24
}
}
},
{ ... }
}
I read that its preferable to use composite columns instead of super columns, so I need an example of the best way to implement this. My queries are like:
Get items for box by Id
get top 20 boxes with their items (for displaying a range of boxes with their items on the page)
update items size by item id (increment size by a number)
get all boxes by userid (all boxes that belongs to a specific user)
I am expecting lots of writes to change the size of each item in the box. I want to know the best way to implement it without the need to use super columns. Furthermore, I don't mind getting a solution that takes Cassandra 1.2 new features into account, because I will use that in production.
Thanks
This particular model is somewhat challenging, for a number of reasons.
For example, with the box ID as a row key, querying for a range of boxes will require a range query in Cassandra (as opposed to a column slice), which means the use of an ordered partitioner. An ordered partitioner is almost always a Bad Idea.
Another challenge comes from the need to increment the item size, as this calls for the use of a counter column family. Counter column families store counter values only.
Setting aside the need for a range of box IDs for a moment, you could model this using multiple tables in CQL3 as follows:
CREATE TABLE boxes (
id int PRIMARY KEY,
belongs_to_user text,
box_title text,
);
CREATE INDEX useridx on boxes (belongs_to_user);
CREATE TABLE box_items (
id int,
item int,
size counter,
PRIMARY KEY(id, item)
);
CREATE TABLE box_item_names (
id int PRIMARY KEY,
item int,
name text
);
BEGIN BATCH
INSERT INTO boxes (id, belongs_to_user, box_title) VALUES (23442, 'user1', 'the box title');
INSERT INTO box_items (id, item, name) VALUES (23442, 1, 'itemname1');
INSERT INTO box_items (id, item, name) VALUES (23442, 1, 'itemname2');
UPDATE box_items SET size = size + 44 WHERE id = 23442 AND item = 1;
UPDATE box_items SET size = size + 24 WHERE id = 23442 AND item = 2;
APPLY BATCH
-- Get items for box by ID
SELECT size FROM box_items WHERE id = 23442 AND item = 1;
-- Boxes by user ID
SELECT * FROM boxes WHERE belongs_to_user = 'user1';
It's important to note that the BATCH mutation above is both atomic, and isolated.
Technically speaking, you could also denormalize all of this into a single table. For example:
CREATE TABLE boxes (
id int,
belongs_to_user text,
box_title text,
item int,
name text,
size counter,
PRIMARY KEY(id, item, belongs_to_user, box_title, name)
);
UPDATE boxes set size = item_size + 44 WHERE id = 23442 AND belongs_to_user = 'user1'
AND box_title = 'the box title' AND name = 'itemname1' AND item = 1;
SELECT item, name, size FROM boxes WHERE id = 23442;
However, this provides no guarantees of correctness. For example, this model makes it possible for items of the same box to have different users, or titles. And, since this makes boxes a counter column family, it limits how you can evolve the schema in the future.
I think in PlayOrm's objects first, then show the column model below....
Box {
#NoSqlId
String id;
#NoSqlEmbedded
List<Item> items;
}
User {
#NoSqlId
TimeUUID uuid;
#OneToMany
List<Box> boxes;
}
The User then is a row like so
rowkey = uuid=<someuuid> boxes.fkToBox35 = null, boxes.fktoBox37=null, boxes.fkToBox38=null
Note, the form of the above is columname=value where some of the columnnames are composite and some are not.
The box is more interesting and say Item has fields name and idnumber, then box row would be
rowkey = id=myid, items.item23.name=playdo, items.item23.idnumber=5634, itesm.item56.name=pencil, items.item56.idnumber=7894
I am not sure what you meant though on get the top 20 boxes? top boxes meaning by the number of items in them?
Dean
You can use Query-Driven Methodology, for data modeling.You have the three broad access paths:
1) partition per query
2) partition+ per query (one or more partitions)
3) table or table+ per query
The most efficient option is the “partition per query”. This article can help you in this case, step-by-step. it's sample is exactly a one-to-many relation.
And according to this, you will have several tables with some similar columns. You can manage this, by Materialized View or batch-log(as alternative approach).

Cassandra: Update multiple rows?

In mysql, I can do the following query, UPDATE mytable SET price = '100' WHERE manufacturer='22'
Can this be done with cassandra?
Thanks!
For that you will need to maintain your own index in a separate column family (you need a way to find all products (product ids) that are manufactured by a certatin manufacturer. When you have all the product ids doing a batch mutation is simple).
E.g
ManufacturerToProducts = { // this is a ColumnFamily
'22': { // this is the key to this Row inside the CF
// now we have an infinite # of columns in this row
'prod_1': "prod_1", //for simplicity I'm only showing the value (but in reality the values in the map are the entire Column.)
'prod_1911' : null
}, // end row
'23': { // this is the key to another row in the CF
// now we have another infinite # of columns in this row
'prod_1492': null,
},
}
(disclaimer: thanks Arin for the annotation used above)