Filtering on ag-grid serverside not setting start row to 0 and end row to 100 - ag-grid

Really need help on this, please.
Brief: I have implemented ag-grid serverside mode with partial store for lazy loading.
Problem Scenario : ServerSide mode, what happens is as you scroll more data is loaded, in terms of ag-grid more row blocks are loaded.
Lets say block size is 100 rows.
I scrolled 5-6 times, 5-6 request went to the server , loaded the data into the grid using success callback of getRows method in ServerSideDataSource Implementation.
You are currently viewing 500th-600th row in your viewport(the last request that went to server).
If you go and apply a fresh/change-existing filter on a column, the getRows method will get called but with request params having startRow 500 and endRow 600(rowBlock you are currently viewing).
This is the issue. I want that to be 0 and 100 respectively as you generally implement server-side filtering. It should be a fresh request to server right. ag-grid should recognise a new filter got applied so dump the existing rows on the grid send fresh request to server with 0 and 100 values.
This start and end row values are fine when you have already loaded data with filter applied till 500 and scrolling to load 500-600. But when the filter is first applied/ freshly applied(change from existing filter/ newly applied) you need the start and end rows to be 0 and 100 right. Help!!

Hi i came across this question while searching for this exact problem, looking around to the docs and couldn't find solution there. It's happening after they introduce serverSideStoreType: "partial | full".
my current workaround for this is to updating params.request.filterModel on your getRows datasource, if detect any changes on filterModel
getRows: function (params) {
//update startRow to 0 then detect changes
if(grid.filterModel != JSON.stringify(params.request.filterModel) ){
params.request.startRow = 0;
}
grid.filterModel = JSON.stringify(params.request.filterModel);

I got a method,after filter changed grid will be scrolled to the first row.
Angular :
filterChanged(params: FilterChangedEvent): void {
this.gridApi.ensureIndexVisible(0,null);
}
Javascript :
filterChanged(params) {
gridOptions.api.ensureIndexVisible(0,null);
}

Related

Avoiding repetitive calls when creating reactfire hooks

When initializing a component using reactfire, each time I add a reactfire hook (e.g. useFirestoreDocData), it triggers a re-render and therefore repeats all previous initialization. For example:
const MyComponent = props => {
console.log(1);
const firestore = useFirestore();
console.log(2);
const ref = firestore.doc('count/counter');
console.log(3);
const { value } = useFirestoreDocDataOnce(ref);
console.log(4);
...
return <span>{value}</span>;
};
will output:
1
1
2
3
1
2
3
4
This seems wasteful, is there a way to avoid this?
This is particularly problematic when I need the result of one reactfire hook to create another (e.g. retrieve data from one document to determine which other document to read) and it duplicates the server calls.
See React's documentation of Suspense.
Particulary that part: Approach 3: Render-as-You-Fetch (using Suspense)
Reactfire uses this mechanics. It is not supposed to fetch more than one time for each call even if the line is executed more than once. The mechanics behind "understand" that the fetch is already done and will start the next one.
In your case, react try to render your component, see it needs to fetch, stop rendering and show suspense's fallback while fetching. When fetch is done it retry to render your component and as the fetch is completed it will render completely.
You can confirm in your network tab that each calls is done only once.
I hope I'm clear, please don't hesitate to ask for more details if i'm not.

Wait for backend service response before making changes to ag-grid table

I am using ag-grid/ag-grid-angular to provide an editable grid of data backed by a database. When a user edits a cell I want to be able to post the update to the backend service and if the request is successful update the grid and if not undo the user's changes and show an error.
I have approached this problem from a couple different angles but have yet to find the solution that meets all my requirements and am also curious about what the best practice would be to implement this kind of functionality.
My first thought was to leverage the cellValueChanged event. With this approach I can see the old and new values and then make a call to my service to update the database. If the request is successful then everything is great and works as expected. However, if the request fails for some reason then I need to be able to undo the user's changes. Since I have access to the old value I can easily do something like event.node.setDataValue(event.column, event.oldValue) to revert the user's changes. However, since I am updating the grid again this actually triggers the cellValueChanged event a second time. I have no way of knowing that this is the result of undoing the user's changes so I unnecessarily make a call to my service again to update the data even though the original request was never successful in updating the data.
I have also tried using a custom cell editor to get in between when the user is finished editing a cell and when the grid is actually updated. However, it appears that there is no way to integrate an async method in any of these classes to be able to wait for a response from the server to decide whether or not to actually apply the user's changes. E.g.
isCancelBeforeStart(): boolean {
this.service.updateData(event.data).subscribe(() => {
return false;
}, error => {
return true;
});
}
does not work because this method is synchronous and I need to be able to wait for a response from my service before deciding whether to cancel the edit or not.
Is there something I am missing or not taking in to account? Or another way to approach this problem to get my intended functionality? I realize this could be handled much easier with dedicated edit/save buttons but I am ideally looking for an interactive grid that is saving the changes to the backend as the user is making changes and providing feedback in cases where something went wrong.
Any help/feedback is greatly appreciated!
I understand what you are trying to do, and I think that the best approach is going to be to use a "valueSetter" function on each of your editable columns.
With a valueSetter, the grid's value will not be directly updated - you will have to update your bound data to have it reflected in the grid.
When the valueSetter is called by the grid at the end of the edit, you'll probably want to record the original value somehow, update your bound data (so that the grid will reflect the change), and then kick off the back-end save, and return immediately from the valueSetter function.
(It's important to return immediately from the valueSetter function to keep the grid responsive. Since the valueSetter call from the grid is synchronous, if you try to wait for the server response, you're going to lock up the grid while you're waiting.)
Then, if the back-end update succeeds, there's nothing to do, and if it fails, you can update your bound data to reflect the original value.
With this method, you won't have the problem of listening for the cellValueChanged event.
The one issue that you might have to deal with is what to do if the user changes the cell value, and then changes it again before the first back-end save returns.
onCellValueChanged: (event) => {
if (event.oldValue === event.newValue) {
return;
}
try {
// apiUpdate(event.data)
}
catch {
event.node.data[event.colDef.Field] = event.oldValue;
event.node.setDataValue(event.column, event.oldValue);
}
}
By changing the value back on node.data first, when setDataValue() triggers the change event again, oldValue and newValue are actually the same now and the function returns, avoiding the rather slow infinite loop.
I think it's because you change the data behind the scenes directly without agGrid noticing with node.data = , then make a change that agGrid recognises and rerenders the cell by calling setDataValue. Thereby tricking agGrid into behaving.
I would suggest a slightly better approach than StangerString, but to credit him the idea came from his approach. Rather than using a test of the oldValue/newValue and allowing the event to be called twice, you can go around the change detection by doing the following.
event.node.data[event.colDef.field] = event.oldValue;
event.api.refreshCells({ rowNodes: [event.node], columns: [event.column.colId] });
What that does is sets the data directly in the data store used by aggrid, then you tell it to refresh that grid. That will prevent the onCellValueChanged event from having to be called again.
(if you arent using colIds you can use the field or pass the whole column, I think any of them work)

AG-Grid get page number with infinite scrolling

I'm using the AG-Grid infinite scrolling row model in Angular, by following the example from Here
When running the above example, I can see in the developer tools that the page number gets logged out:
However I cannot seem to find a way to get the page number in my code. I've tried paginationGetCurrentPage(), however that doesn't appear to work with the infinite scrolling row model.
Is there any way to get the page number being requested when the getRows functions is fired? My api expects a page number to retrieve data, rather than a start and end row number.
It's just simple math you need to do to get the page number inside getRows.
let pageNo = 1;
if (this.paginationPageSize != undefined)
pageNo = params.startRow / this.paginationPageSize + 1;
// use pageNo to make API request
console.log('pageNo: ' + pageNo);
Check this plunk I've created. Observe the browser logs.

Ag-Grid how to start loading records from the 500th?

I have a Ag-grid configured to work in infinity scroll
In the documentation, i found this example, which shows how to make a jump to the 500th record
But I'm looking for a way to start loading the grid directly to the 500th record
Maybe there is a property to set in the grid?
Or should I put in some event this code:
jumpTo500() {
if (this.gridApi.getInfiniteRowCount() < 501) {
this.gridApi.setInfiniteRowCount(501, false);
}
this.gridApi.ensureIndexVisible(500);
}
Which?
you can use ensureIndexVisible on onGridReady stage:
onGridReady(params) {
this.gridApi = params.api;
this.gridColumnApi = params.columnApi;
this.gridApi.ensureIndexVisible(499); <--- add this line
Note : this.gridApi.ensureIndexVisible(numberValue) number value should be less than infiniteInitialRowCount atleast for 1
infiniteInitialRowCount = 1000 - initial config
this.gridApi.ensureIndexVisible(999) - max
Update: another possible way via firstDataRendered
firstDataRendered Fired the first time data is rendered into the grid.
(firstDataRendered)="firstDataRendered($event)"
...
firstDataRendered(){
this.gridApi.ensureIndexVisible(499);
}
The ag-grid has a bug in infinity scroll mode
They are working to fix the bug
The solution proposed here is the best workaround I have found so far
But it does not permanently resolve the performance bug
In fact, looking in the logs you can see that the program always makes a first unnecessary request, to view the first 100 records
Only then, the workaround requires the correct records from 400 to 500

DevExpress VerticalGrid in unbound mode with MultiRecordLayout

EDIT: As it turns out, the grid does not support unbound mode in MultiRecordView layout.
I will try to ask this question a different way since my last one was downvoted without comment, so I don't know what the downvoter was objecting to.
I've worked quite a lot with the DevExpress VerticalGrid in unbound mode in SingleRecordView. We use it in all of our desktop applications that involve lots of data-entry. All data-entry forms are consistent in look-and-feel and so user training is minimal. I think it is a great control.
However, I don't understand how to use it in unbound mode in MultiRecordView layout. I cannot even figure out how to populate the unbound grid with the data for several records. In SingleRecord layout, I use the RowsIterator to move data from my data object in memory into the corresponding row/cell in the VerticalGrid's single record.
But in MultiRecordView layout, I can't figure out how to add the second record and the third record, etc etc, and position the current record pointer so that the RowsIterator is working with the rows of the correct record.
A small code snippet, showing how to move the current record pointer when adding the second and subsequent records in MultiRecordView, would be very helpful.
I've tried AddNewRecord() and setting the FocusedRecord but without success:
for (int i = 0; i < MyTable.Rows.Count; i++)
{
vGridControl1.AddNewRecord();
vGridControl1.FocusedRecord = i;
vGridControl1.RowsIterator.DoOperation(new DataPuller(MyTable.Rows[i]));
}
and here's a relevant snippet from my DataPuller object:
public override void Execute(DevExpress.XtraVerticalGrid.Rows.BaseRow brow)
{
//<snip>
if (brow is DevExpress.XtraVerticalGrid.Rows.EditorRow)
{
string fieldname = brow.Properties.FieldName;
if (table.Columns.Contains(fieldname))
{
brow.Properties.Value = (table[fieldname] == DBNull.Value) ? null : table[fieldname];
}
}
//<snip>
}
The vertical grid doesn't support unbound mode when in MultiRecordView layout.