PrimeVue DataTable Column Sort by Date/Time - javascript

I have a PrimeVue DataTable (https://primefaces.org/primevue/datatable) that is arranged as such:
<DataTable
:rows = "5"
:value = "apiItems"
>
<Column
v-for="data in columns"
:field="data.field"
:header="data.header"
:key="data.field"
:sortable="true"
/>
</DataTable>
Where the table is being populated by data received from an API call, and the field layout is as listed:
const columns = [
{ field: 'initialDate', header: 'Initial Date'},
{ field: 'finishDate', header: 'Finish Date'}
];
The data being retrieved from the API is in the form of a JS Date() component that is displayed as such: "08/01/2022 08:33:32" for both initialDate and finishDate
How can I the columns via ascending or descending by both the date AND time stamps, whereas now, sorting the columns just rearranges the values based on the first digits available, which happen to be the month; I need them to sort corresponding to not only the correct month, but the time as well.
Any help is appreciated, thanks.

What you are receiving from the API cannot be a Date() object, but is probably a string. And so, if you sort by this column, the rows are sorted lexicographically, but not chronologically.
To avoid that, you should convert the data coming from the API into Date objects. If you convert that to a timestamp, that's very convenient to sort by chronologically:
for (item of apiItems) {
item.initialDateObj = new Date(item.initialDate)
item.initialDateTimestamp = item.intialDateTimeObj.getTime()
}
You can then specify that as the field to sort a column by:
const columns = [
{ field: 'initialDate', sortField: 'initialDateTimestamp', header: 'Initial Date'},
{ field: 'finishDate', sortField: 'finishDateTimestamp', header: 'Finish Date'}
];

Related

Save column header filter in ag-grid in angular

I am working on an existing application in which they have used ag-grid library for angular for most of the grids that they have in their application. Now the ag-grid gives the functionality to filter the grid based on a column value by using the filter option in the column header. I am giving a link to that https://www.ag-grid.com/angular-data-grid/filtering-overview/. I wanted to implement a feature in which we can save the filter keyword that the user is searching for and when he comes back to the same grid the previous filter is already applied. for example https://plnkr.co/edit/?p=preview&preview here we can pick athlete and filter that by going to the column and searching a value so what I want is that if I search 'abc' I should be able to preserve that. is there a way to do that ? I am giving the colDef for the link above
this.columnDefs = [
{ field: 'athlete' },
{
field: 'age',
filter: 'agNumberColumnFilter',
maxWidth: 100,
},
{
field: 'date',
filter: 'agDateColumnFilter',
filterParams: filterParams,
},
{
field: 'total',
filter: false,
},
];
this.defaultColDef = {
flex: 1,
minWidth: 150,
filter: true,
};
}
Any kind of help is appreciated, thanks :)
You can save the filter applied by using the Grid Event onFilterChanged. Inside here you can get the filterModel by calling api.getFilterModel(). In the plunkr below we are showcasing this by saving the filter model to local storage and restoring it by applying it inside the Grid Event onFirstDataRendered
onFilterChanged(params) {
const filterModel = params.api.getFilterModel();
localStorage.setItem('filterModel', JSON.stringify(filterModel));
}
onFirstDataRendered(params) {
const filterModel = JSON.parse(localStorage.getItem('filterModel'));
if (filterModel) {
params.api.setFilterModel(filterModel);
}
}
See this implemented in the following plunkr
You may also find the following documentation pages relevant:
Saving and Restoring Filter Models
Grid Events
To apply existing filters to ag-grid, it can be done using by setting up filterModel on gridApi.
gridApi.getFilterInstance("fieldName").setModel({
"filterType":"equals", //type of filter condition
"type":"text", //Type of column [text/number/date]
"filter":"value" //Value need to be applied as filter.
})
Similarly onFilterChanged event you can capture changes and apply filter dynamically.

Ordering groups individual after renaming

My product table is sorted with initialSort by the product release month ascending. I also grouped my products by a codename which is determinate by the ajax json response url and renamed them to readable names with a groupBy function. Now I want to sort my groups individual without loosing the month sorting in my groups. How is that possible?
var table = new Tabulator("#tableid", {
ajaxURL: url,
layout: "fitColumns",
groupBy: "codename",
groupBy:function(data){
if (data.codename == "X123") {
return "Productname for X123";
}
if (data.codename == "X124") {
return "Productname for X124";
}
…
…
},
initialSort:[
{column:"month", dir:"asc"}
],
columns: [
{ title: "Product", field: "codename"},
{ title: "Month", field: "month"},
…
…
…
]
});
Not exactly sure what you mean by "sort my groups individual", but is this what you're looking for ?
https://jsfiddle.net/r3f7pysw/
initialSort:[
{column:"month", dir:"asc"},
{column:"codename", dir:"asc"}
],
NOTE(1) : I dont think you want to return that string for your grouping, when it seems like its just the header Display string, and you're still going to be sorting on "codename" (becoz the string is the same with a change at the end, which really takes a "little" long to compare each time). But maybe you do...
NOTE(2) : Adding the seconds initialSort is like Ctrl-Click on the sorting to sort by multiple criteria. So if you single click on say, Month, remember that destroys the currentSort array and sets it just to Month.

Numeric column header for parsed CSV in JavaScript

I am using the CSV package for Node to parse some CSV files in a project. I need to be able to handle cases with and without a header. So either of:
const withHeader = `h1,h2,h3
d1a,d2a,d3a
d1b,d2b,d3b`;
const withoutHeader = `d1a,d2a,d3a
d1b,d2b,d3b`;
The number of columns and their names are unknown to my application. Either they will be read from the header, or they should be numerically generated, e.g. col0,col1,col2.
This is where I run into a problem. I always want the output of csvParse to be in object literal form. This is easy when the end-user has indicated that the CSV has a header:
> csvParse(withHeader, {columns: true})
[
{ h1: 'd1a', 'h2': 'd2a', 'h3': 'd3a' },
{ h1: 'd1b', 'h2': 'd2b', 'h3': 'd3b' }
]
But when the user indicates that there is not a header row, it doesn't seem to be possible to end-up with the data in object literal form with programatically generated column headers.
The 3 options for columns are boolean | array | function.
By supplying false, the data returned is an array of arrays, which I would then need to transform into object literal form. Not ideal!
To supply an array of column names, I would already need to know how many columns there are... before it is parsed, which doesn't make sense. I could parse the first row to get the count, then start again supplying the array, but this seems clumsy.
I can supply a function which programmatically generates the column keys. E.g. column => column which doesn't help as a) there is no index supplied, and b) this then ignores the first line as it is assumed to be column headers being transformed into the desired column keys.
Is there a way trick to doing this that I've missed? Here are the two ways that seem clumsier and less efficient than necessary.
Parse 1 row, then parse all
// Obviously in actual use I'd handle edge cases
const colCount = csvParse(withoutHeader, {to_line: 1})[0].length;
// 3
const data = csvParse(withoutHeader, {columns: [...Array(colCount).keys()].map(i => `col{i}`)})
/*
[
{ col0: 'd1a', col1: 'd2a', col2: 'd3a' },
{ col0: 'd1b', col1: 'd2b', col2: 'd3b' }
]
*/
Parse into array of arrays, then convert
csvParse(withoutHeader).map(
row => row.reduce(
(obj, item, index) => {
obj[`col${index}`] = item;
return obj;
},
{}
)
)
/*
[
{ col0: 'd1a', col1: 'd2a', col2: 'd3a' },
{ col0: 'd1b', col1: 'd2b', col2: 'd3b' }
]
*/
To me it would be ideal to be able to specify columns as a function, which was given the column index as an argument instead of a header row.

ValueGetter is not working with grouped rows

When I use valueGetter for columnDefs, instead of showing the values only if the rows are collapsed, it will fill all the cells even if the group is not expanded yet.
Here is an example of the problem
And here is the desired behaviour, I can obtain such a thing with field option:
And here is the code I'm using to define the for each calendar day
{
headerName: moment(day).format("DD"),
colId: moment(day).unix(),
valueGetter: () => "12",
width: 58
}

Why does this datagrid sort in a weird order?

I have a datagrid where each row has a column where I have defined a formatter to format the display result depending on what it says in the database and create a div with a background color depending on the database.
I have this structure for my datagrid:
structure: [
{
name: "Name",
field: "name",
width: "auto"
},
{
name: "Initials",
field: "initials"
},
{
name: "E-mail",
field: "email",
width: "auto"
},
{
name: "Kerberos",
field: "kerberos",
width: "120px",
formatter: function(kerberos){
var format = "";
if(kerberos == "password expired" || kerberos == "account expired"){
format = '<div class="yellow" title="'+kerberos+'">'+kerberos+'</div>';
}else if(kerberos == "ok"){
format = '<div class="green" title="'+kerberos+'">'+kerberos+'</div>';
}else{
format = '<div class="red" title="Has no kerberos account">not available</div>';
}
return format;
}
},
When I press the column header to sort, it sorts the rows, put not consistent, so I don't know if it sorts correctly (see image below). How do I define the way the datagrid have to sort this column?
I was thinking it was the HTML <div...> part I do in the formatter due to the <> characters, but it still sorts weird if I only output the text (which by my understanding, should be sorted alphabetically). Does anyone know why this happens and how I can fix it?
EDIT:
forgot to add how i get/assign data. I get a lot of data from a xhr.post in JSON format, then i do as follows:
dojo.xhr.post({
url: "/cgi-bin/users.cgi",
handleAs: "json",
content: {
psearch: "dojoXhrBlank"
},
load: function(jsondata){
// Creating a store for the datagrid
var personStore = new Memory({ data: jsondata });
// Create datastore for datagrid
var gridStore = ObjectStore({objectStore: personStore});
...
I found an answer. The problem lies in ObjectStore. This store (for some reason) wont sort properly and after changing the store type to ItemFileReadStore it sortet properly. The other reason for switching store was that ItemFileReadStore also supports the comparatorMap attribute which allows for custom sorting, ObjectStore dose not support this attribute.
solution:
load: function(jsondata){
var store = new ItemFileReadStore({
data: { identifier: "id", items: jsondata }
});
pgrid = new DataGrid({
store: store,
...

Categories