Closed gatapia closed 5 years ago
Would be a great feature. Automatically is a nice to have. Best for me if it exposed functions so can hookin and save to remote storage etc
Just looking at source now and it looks like accessing the sort/filter state is simple enough, just attach to onFilter/onSort events. There appears to be now way to set these values back.
Somewhat related, onSort fires the onFilter event even if filter has not changed, i.e. filter data (get filter event), sort data (get filter event then sort event). I think that filter event is redundant. minor issue though.
Is there any update on this issue. I am using the LazyLoad event to store the sort and filter information. I am using local storage (which isn't ideal - but it works). Now when i navigate away from the page with my datatable i can persist those values. Once i return to that page (onInit) i can get those values back from localstorage and use them in very next query (lazy load). HOWEVER, there seems to be no way to visually update the data table UI to show that those filters are being used or that the sort order on a column has changed.
Is there any way to update the datatable header fields on the UI?
This pull request solves this. It uses localStorage for lazy load. Everything is updated visually. For integration with MultiSelect for toggle columns, event onPersistentStateApplied should be used similar to this:
onPersistentStateApplied(event): void { if (!event.state || !event.state.visibleColumnsState) { return; }
let eventColumns = event.state.visibleColumnsState;
this.columns.splice(0, this.columns.length);
for (let i = 0;i < eventColumns.length;i++) {
let eventColumn = eventColumns[i];
this.columns.push({
field: eventColumn.field,
header: eventColumn.header,
style: eventColumn.style
});
}
let columnsOptionsByLabel = {};
for(let i = 0; i < this.columnOptions.length; i++) {
columnsOptionsByLabel[this.columnOptions[i].label] = this.columnOptions[i];
}
for(let j = 0; j < this.columns.length; j++) {
let columnOption = columnsOptionsByLabel[this.columns[j].header];
columnOption.value = this.columns[j];
}
}
Any news on when we might see this released?
This is on roadmap;
https://github.com/primefaces/primeng/wiki/Roadmap
Closing for now and will create a new ticket with details when we pick it up from roadmap after 1.0. At the moment, we're closing tickets that duplicate the upcoming features in roadmap as a part of issue tracker maintenance.
@cagataycivici thanks for the roadmap link - are there any dates pencilled in for when this feature will be released?
any update on this?
Planned for 2.1 due late march.
Similar to PrimeFaces TableState;
https://www.primefaces.org/showcase/ui/data/datatable/tableState.xhtml
@cagataycivici do you have a new planning for this feature?
Yes, but can't give a specific date right now. Rough estimation is in 2 months.
Love ngPrime but this is a major issue with an otherwise great data table. In the meantime, are there any events we could subscribe to and properties we could set that would allow us to implement this ourselves?
@TimKohler -- I solved this manually using something like this:
public gridOptions = {
first: 0,
rows: 10,
sortField: 'title',
sortOrder: 1
};
onSort(e: { field: string, order: number }) {
this.gridOptions.sortField = e.field;
this.gridOptions.sortOrder = e.order;
this.gridOptions.first = 0;
this.localStorageService.set('my-grid-options', this.gridOptions);
}
onPage(e: { first: number, rows: number }) {
this.gridOptions.rows = e.rows;
this.gridOptions.first = e.first;
this.localStorageService.set('my-grid-options', this.gridOptions);
}
ngOnInit() {
// after loading the table data then read the options and
// if options exist set them wrapped in setTimeout():
const opt = this.localStorageService.get('my-grid-options');
if (opt) {
setTimeout(() => {
this.gridOptions = opt;
this.dataTable.sortField = this.gridOptions.sortField;
this.dataTable.sortOrder = this.gridOptions.sortOrder;
this.dataTable.sortSingle();
this.dataTable.paginate(this.gridOptions);
this.blocked = false;
}, 0);
return;
}
}
The table looks like:
<p-dataTable #dt [value]="sets" (onRowClick)="select($event.data)" [paginator]="true"
paginatorPosition="both" [pageLinks]="10" [rows]="10" [rowsPerPageOptions]="[5,10,20,30,40]"
(onPage)="onPage($event)" (onSort)="onSort($event)">
@jamesgroat Thank you! This is a great workaround. Got it working well.
Yes, there are events to use until this is built-in.
I cannot get pagination to stick with the newest version of PrimeNG, since paginate()
no longer accepts any arguments.
Does anyone have a solution? Here is my current code:
onPage(e: { first: number, rows: number }) {
console.log(this.dataTable.first);
this.gridOptions.rows = e.rows;
this.gridOptions.first = e.first;
localStorage.setItem(this.optionsKey, JSON.stringify(this.gridOptions));
}
const opt = localStorage.getItem(this.optionsKey);
const filters = localStorage.getItem("filters");
if (opt) {
let go = JSON.parse(opt);
setTimeout(() => {
this.gridOptions = go;
this.dataTable.sortField = this.gridOptions.sortField;
this.dataTable.sortOrder = this.gridOptions.sortOrder;
this.dataTable.sortSingle();
this.dataTable.first = this.gridOptions.first;
this.dataTable.rows = this.gridOptions.rows;
this.dataTable.paginate();
//this.dataTable.paginate(this.gridOptions);
if (filters) {
console.log(JSON.parse(filters));
this.dataTable.filters = JSON.parse(filters);
}
}, 0);
@blgrnboy Try this:
this.gridOptions = opt;
this.dataTable.sortField = this.gridOptions.sortField;
this.dataTable.sortOrder = this.gridOptions.sortOrder;
this.dataTable.sortSingle();
this.dataTable.onPageChange(this.gridOptions);
I don't think you need these:
this.dataTable.first = this.gridOptions.first;
this.dataTable.rows = this.gridOptions.rows;
@jamesgroat I tried that, with no success.
@blgrnboy make sure you are calling that code after you have loaded your data?
@jamesgroat My sort and filter settings are working and persisting as expected, so I would expect pagination to work as well. I did try moving around the code anyway, but still doesn't seem to work.
@cagataycivici Could you please help out with this?
Any Updates on this?
The workarounds are quite nice, but don't cover all use cases.
Besides rows setting I need to persist column visibility, order and width.
For width there isn't an API as far as I could see in the typings, so I iterate over the columns DOM and get them by clientWidth, which is quite ugly and it's not that reliable I think.
Also widths behave weirdly on resetting my config for table and some columns with fixed set width through style property grow ridiculously large on reset.
Planned for 2.1 due late march.
primeng is on 4.2.2 now, is there a new concrete milestone for this on the horizon?
Don't like to annoy you, I know it's open source, but it would be quite unsatisfactory to implement it on my own if this comes anytime soon.
Really love your table otherwise and would appreciate an answer :)
Edit:
Okay, since my Product Owner wants this feature ASAP, I'll try to implement it, is there any place to start besides the table source file (and of course the official documentation)? Any Developer Documentation, some coding conventions to follow, so I could make a PR some day?
Hello @fberthel
Did you find a workaround for persistant width, visibility and order of columns ? I'm having the same issue, and I have implemented a similar solution for column width, but I can't seems to find a way to implement persistent order other than rendering datatable everytime. (I don't want to use Javascript method in my typescript file...).
Thanks for the help :) This is a great datatable overall, I just thinks it's missing some features.
@fberthel, I second that. Did you get it working?
I couldn't get the filters working. Though i can retrieve the filter value and the corresponding column. The filter is not getting applied to the datatable. filters:FilterMetadata={};
while storing this.dataTableState={ groupField:this.dataTable.groupField, multiSortMeta:this.dataTable.multiSortMeta, filters:this.dataTable.filters }; while retrieving, I'm using this.dataTable.filters=this.dataTableState.filters;
Hey guys,
Sorry for letting you down so long, had tons of work to do. I'll try to make it up with you.
We didn't extend the DataTable itself, but build some code around it so it works for us.
I've made a StackBlitz project where you can change width and order of columns, also visibility, but it messes around with the width of columns, don't know what's going on there. (Will have a look into the docs later) https://angular-primeng-tableconfig-demo.stackblitz.io
Feel free to play around, fork it, extend it, etc pp.
Side note: We got it working for our solution, but I can't post the exact code, on the one hand it's business code, and on the other hand it would be way to much to have a chance to understand it. It's still quite complex and not really minimal. The Visibility issues in the StackBlitz project are only there, in our solution it's working, but i can't tell why. Like I said, way more code than here, I'll try to figure it out and boil it down.. Also Pagination with page-size is not there and persisted now, I'll try to add that, again, it's different in our own project as we need full access to pagination (server-side-pagination) and therefore we needed to make it external, as the API through the DataTable is not nearly as large as for an isolated paginator component..
It doesn't feel good to add tons of "exoskeleton"-code to the DataTable, we didn't know how to include it. Like I said we also need server-side-features, so all filters, sort methods, data and pagination APIs would need rework, which would result in a huge PR. I hope the new TurboTable (nice name btw 😄 ) will get some of those extensions in the future. Also I dont like how we are iterating over DOM-Nodes in terms of widths calculation and setting it, but that was the way it worked, so don't be too harsh on us please 🤓
Hope this attempt will help some of you.
Edit: Found out that visibility issue is something we fixed directly in primeng but didn't pass in as Pull Request. PR probably wouldn't be accepted as DataTable is already deprecated.
diff --git a/src/app/components/datatable/datatable.ts b/src/app/components/datatable/datatable.ts
index 6073cc5..82fe13f 100644
--- a/src/app/components/datatable/datatable.ts
+++ b/src/app/components/datatable/datatable.ts
@@ -2196,9 +2196,12 @@ export class DataTable implements AfterViewChecked,AfterViewInit,AfterContentIni
if(columnWidth + delta > parseInt(minWidth)) {
if(this.columnResizeMode === 'fit') {
let nextColumn = this.resizeColumn.nextElementSibling;
+ while(nextColumn.classList.contains("ui-helper-hidden")){
+ nextColumn = nextColumn.nextElementSibling;
+ }
let nextColumnWidth = nextColumn.offsetWidth - delta;
- if(newColumnWidth > 15 && nextColumnWidth > 15) {
+ if(nextColumn && newColumnWidth > 15 && nextColumnWidth > 15) {
Hi, any update on this feature.
I've updated the StackBlitz to use the TurboTable, there is no workaroung needed anymore for columns widths if I've looked at it correctly. Otherwise the limitations still stand and it's still just external code.
Demo: https://angular-primeng-tableconfig-demo.stackblitz.io Code: https://stackblitz.com/edit/angular-primeng-tableconfig-demo
features so far:
Still quite far away from the inital post state requirements though..
Thanks for the great table guys 🎉
Hello! Has any progress been made on this feature?
Scheduled for 6.1.
Thank you for your prompt reply. Eagerly awaiting this feature. Any tentative dates for 6.1.0?
Hi there !
Do we have any update within due date of Roadmap point: "State saving featuring across views"? I'm really looking forward to use the solution in PROD project.
BTW. do you know any working TurboTable workaround to save / apply filters state? If you can advise me somehow which method / strategy can be used to apply previously saved filters into the UI controls lik dropdowns, inputs etc., would be grateful.
When implementing the feature, please make sure to include the sorting and paging state as well.
I did implement a workaround for storing the filter state between page views (though not paging nor sorting). Basically:
Edit: You can also store the current page state by storing the table's first property in session and setting it during ngOnInit as well. I just implemented it and it works.
@AlejandroFlorin , could you please share your workaround solution of applying filters state to the TurboTable?
@emilwaw This is an untested trimmed down version of my code. but it should give you the idea.
Edit: Made a couple of corrections. I missed the pagingFirstIndex in a couple of places.
Edit2: Simplification - Turns out don't need this.pagingFirstIndex nor the onPage handler
Provide the guard service in AppModule
//app-module.ts
import { DeactivateGuardService } from 'app/core/services/deactivate-guard.service';
...
@NgModule({
declarations: [...],
imports: [...],
providers: [
...,
DeactivateGuardService]
})
export class AppModule {
}
Define the route guard:
//deativate-guard.service.ts
import { Injectable } from '@angular/core';
import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/observable';
export interface CanComponentDeactivate {
canDeactivate: (
currentRoute: ActivatedRouteSnapshot,
currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot
) => Observable<boolean> | Promise<boolean> | boolean;
}
@Injectable()
export class DeactivateGuardService implements CanDeactivate<CanComponentDeactivate>{
canDeactivate(
component: CanComponentDeactivate,
currentRoute: ActivatedRouteSnapshot,
currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot
) {
return component.canDeactivate ? component.canDeactivate(currentRoute, currentState, nextState) : true;
}
}
Enable the deactivate guard service in your module's routes:
//table-state-store.module.ts
//Angular
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
//Vendors
import { InputTextModule } from 'primeng/primeng';
import { TableModule } from 'primeng/table';
//App
import { DeactivateGuardService } from "[path]/deactivate-guard.service";
const routes: Routes = [
{
path: '',
canDeactivate: [DeactivateGuardService],
component: sample_table_state_store.component.ts,
}
];
@NgModule({
imports: [
CommonModule,
ReactiveFormsModule,
RouterModule.forChild(routes)],
declarations: [...],
exports: [...]
})
export class SampleTableStateModule { }
Define the table's data set and an interface for the object that will be stored in session:
//TableData.ts
import { FilterMetadata } from 'primeng/primeng';
export interface TableData {
id: number;
name: string;
}
export interface TableState {
idFilter: number;
nameFilter: string;
pagingFirstIndex: number;
filters: {
[s: string]: FilterMetadata;
};
}
And the component:
// sample_table_state_store.component.ts
//Angular
import {
Component,
OnInit,
ViewChild
} from "@angular/core";
import { Router } from '@angular/router';
import {
FormBuilder,
FormGroup,
FormControl,
FormControlName
} from '@angular/forms';
import { CanComponentDeactivate } from "app/core/services/deactivate-guard.service";
//App
import { Data, State } from "[path]/TableData";
export class SampleTableStateStore implements
OnInit,
CanComponentDeactivate {
@ViewChild('myTable') myTable: Table;
form: FormGroup;
data: Data[]
get idFilter(): FormControl {
return this.form.get('idFilter') as FormControl;
}
get nameFilter(): FormControl {
return this.form.get('nameFilter') as FormControl;
}
constructor() {
this.form = this.fb.group({
idFilter: [''],
nameFilter: ['']
}
ngOnInit() {
let tableState = JSON.parse(sessionStorage.getItem('TableState')) as TableState;
if (tableState) {
this.idFilter.setValue(tableState.id);
this.nameFilter.setValue(tableState.name);
this.myTable.filters = tableState.filters;
this.myTable.first = tableState.pagingFirstIndex;
}
}
canDeactivate() {
sessionStorage.setItem(
'TableState',
JSON.stringify(
{
id: this.idFilter.value,
name: this.nameFilter.value,
pagingFirstIndex: this.myTable.first,
filters: this.myTable.filters
} as TableState)
);
return true;
}
//rest of the component code, including filling the table Data array
...
}
@cagataycivici What does it mean that this was removed from the milestone/version again?
Thanks!
@cagataycivici, what is the next alternative date of potential TableState functionality implementation ? Do you plan to implement it at all ?
Yes we'll work on it for 7.0. It will be one of the highlight of 7.0 in terms of new stuff.
This is happening but should we use sessionstorage, localstorage or a service for this? We can't decide over here :). Any ideas?
When I implemented this with angularjs's ui-grid, I used localStorage. My customers want their states to be there when they come back another day. sessionStorage is simply too short lived for this kind of thing. And technically if you used localStorage, you could also use an expiration date kinda deal, so the developer could choose how long it's stored. But that's not really common i'd guess. That said, the option/ability to store this server-side would also be nice, via a provided callback of some sort.
Just my .02 cents.
I implemented it using Session Storage as we didn't need it to persist between browser sessions but local storage gives devs the most options as they can clear it on logout if they want. A service would lose state between browser windows so that would be the most restrictive. I vote Local Storage since it is the most flexible IMO.
What about providing some storage service interface (with default implementation e.g. localstorage) which could be implemented by user when needed, and overridden at DI level (whole app / per module / per component)?
I also suggest to make this feature optional (disabled by default), because from my perspective table should contain minimal (or none) internal state.
local storage please. Kind Regards,
Nandesh
On Wed, 24 Oct 2018 at 18:36, Lukáš Kováč notifications@github.com wrote:
What about providing some storage service interface (with default implementation e.g. localstorage) which could be implemented by user when needed, and overridden at DI level (whole app / per module / per component)?
I also suggest to make this feature optional (disabled by default), because from my perspective table should contain minimal (or none) internal state.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/primefaces/primeng/issues/304#issuecomment-432732504, or mute the thread https://github.com/notifications/unsubscribe-auth/ALEgmgf-5YiYHbWouGmtg2qG0o-bvitJks5uoJb8gaJpZM4IWkG6 .
As part of this, would it make sense to add a new supported state to the table, specifically column visibility? Right now it's only possible by ngIf'ing the column. If one were to add a way for users to hide columns (outside of p-table), there would likely not be a way to pass that into whatever state is saved as it stands.
2 years for a mandatory feature.. who use a table with filters without saving it ? :/
In progress...
Is this issue include the state of columns resize ? I have manage the state of order and toggle but I can't find any solution for resize
https://stackblitz.com/edit/angular-primeng-table-order-resize-toggle
Implemented now, usage is simple as defining stateStorage to selected where to keep it e..g sessionStorage or localStorage along with the state key;
<p-table[columns]="cols" [value]="cars" stateStorage="session | local" stateKey="key1">
Currently supported features that can be stateful are;
I'll mark it as resolved after doing the docs tomorrow. Thank you for all the feedback on the initial version.
Ready for a test drive in upcoming 7.0.0-RC1.
It would be good to be able to remember the state of the table to be able to give the user continuity as they use an application. This state would include:
A nice clean API to get and set this would be great:
Or perhaps even a totally automatic API, like: