In ag-grid, are status bars supported in the server side model? - ag-grid

I've created the following Plunkr:
https://plnkr.co/edit/UX7qeeul5SfWXtV9rYcf?p=preview
and have added the following code:
statusBar: {
statusPanels: [
{ statusPanel: 'agFilteredRowCountComponent' },
{ statusPanel: 'agSelectedRowCountComponent' },
{ statusPanel: 'agAggregationComponent' }
]
},
from:
https://www.ag-grid.com/javascript-grid-status-bar/#example-status-bar-simple
However, I am not getting status bars.
Are they supported in the server side model?

Seems that is an issue of default statusPanel.
Cuz I've checked with custom and it works, here is a sample
*check console, getRangeSelections and getSelectedRows works as expected, so you can try to create own statusPanel with same logic while it wouldn't be fixed.

I believe the issue with your specific example is that you are unable to actually select a ROW of data in your example. Instead you seem to only be able to select individual nodes. The status bar will only appear if an entire row is selected regardless on the data source
As well this is an excerpt from filterRowsComp.ts line 26 for within Ag grid:
// this component is only really useful with client side rowmodel
if (this.gridApi.getModel().getType() !== 'clientSide') {
console.warn(`ag-Grid: agFilteredRowCountComponent should only be used with the client side row model.`);
return;
}
Showing that the default filtered data status bar panels will only work correctly with client side data.

Related

How can I update data within Detail table and don't loose range selection and filters?

I have latest enterprise React agGrid table with Master/Detail grid. My data is fetched on the client every 5 seconds and then put immutably to the redux store. React grid component is using deltaRowDataMode={true} props and deltaRowDataMode: true in Detail options.
My master grid performs normally as expected: if I have range selected, grid would keep selection after the data updates, so would filters and visibility menu would be still opened. But Detail grid behaves differently: on data refresh selections are being removed, visibility menu closes and grid jumps if filters were changed.
I've read in docs that when I open Detail grid it's being created from scratch, but in my case I don't close Detail. Anywhere I've tried keepDetailRows=true flag, which solved problems with jumping on update and selection loss, but Detail grid doesn't update data now.
It seems there are only two possible options according to the docs https://www.ag-grid.com/javascript-grid-master-detail/#changing-data-refresh. The first one is a detail table redraws everytime a data in a master row changes and the second one is a detail row doesn't changes at all if a flag suppressRefresh is enabled. Strange decision, awful beahviour...
Update.
Hello again. I found a coupe of solutions.
The first one is to use a detailCellRendererParams in table's options and set suppressRefresh to true. It gives an opportunity to use getDetailGridInfo to get detail-table's api.
While the detail-table's refreshing is disabled, using detailGridInfo allows to set a new data to a detail-table.
useEffect(() => {
const api = gridApiRef;
api && api.forEachNode(node => {
const { detailNode, expanded } = node;
if (detailNode && expanded) {
const detailGridInfo = api.getDetailGridInfo(detailNode.id);
const rowData = detailNode.data.someData; // your nested data
if (detailGridInfo) {
detailGridInfo.api.setRowData(rowData);
}
}
});
}, [results]);
The second one is to use a custom cellRenderer, wicth is much more flexible and allows to use any content inside a cellRenderer.
In table's options set detailCellRenderer: 'yourCustomCellRendereForDetailTable.
In yourCustomCellRendereForDetailTable you can use
this.state = {
rowData: [],
}
Every cellRenderer has a refresh metod which can be used as follow.
refresh(params) {
const newData = [ ...params.data.yourSomeData];
const oldData = this.state.rowData;
if (newData.length !== oldData.length) {
this.setState({
rowData: newData,
});
}
if (newData.length === oldData.length) {
if (newData.some((elem, index) => {
return !isEqual(elem, oldData[index]);
})) {
this.setState({
rowData: newData,
});
}
}
return true;
}
Using method refresh this way gives a fully customizable approach of using a detailCellRenderer.
Note. To get a better performance with using an immutable data like a redux it needs to set immutableData to true in both main and detail tables.

ag-grid - how to get parent node from child grid via context menu?

As an example, I have a Master\Detail grid.
Master\Detail defined as key-relation model and on getDetailRowData method parent node data exists in params
but how to get parent node data from child view?
Tried via context-menu:
On right click - getContextMenuItems got executed which has an input params
On this sample, child-grid doesn't have any row and node in context-params is null, it's ok,
but anyway it should be possible to retrieve the parent details at least via grid API, isn't it ?
Then I've tried to get parent via node:
but instead of detail_173 as you can see its ROOT_NODE_ID, and here is a confusion for me.
So question is that how to get parent node data (RecordID 173 just in case) through child-view context menu or any other possible way (without storing temp value, cuz multiple children's could be opened at the same time)
Yes, I've read this part Accessing Detail Grid API, and still unclear how to get parent-node via child-grid.
For React Hook users without access to lifecycle methods, use Ag-Grid Context to pass the parent node (or parent data) to the detail grid via detailGridOptions. No need to traverse the DOM or use a detailCellRenderer unless you want to :)
https://www.ag-grid.com/javascript-grid-context/
detailCellRendererParams: (masterGridParams) => ({
detailGridOptions: {
...
context: {
masterGrid: {
node: masterGridParams.node.parent,
data: masterGridParams.data
}
},
onCellClicked: detailGridParams => {
console.log(detailGridParams.context.masterGrid.node);
console.log(detailGridParams.context.masterGrid.data);
}
}
})
Able to achieve it. Have a look at the plunk I've created: Get master record from child record - Editing Cells with Master / Detail
Right click on any child grid's cell, and check the console log. You'll be able to see parent record in the log for the child record on which you've click.
The implementation is somewhat tricky. We need to traverse the DOM inside our component code. Luckily ag-grid has provided us the access of it.
Get the child grid's wrapper HTML node from the params - Here in the code, I get it as the 6th element of the gridOptionsWrapper.layoutElements array.
Get it's 3rd level parent element - which is the actual row of the parent. Get it's row-id.
Use it to get the row of the parent grid using parent grid's gridApi.
getContextMenuItems: (params): void => {
var masterId = params.node.gridOptionsWrapper.layoutElements[6]
.parentElement.parentElement.parentElement.getAttribute('row-id');
// get the parent's id
var id = masterId.replace( /^\D+/g, '');
console.log(id);
var masterRecord = this.gridApi.getRowNode(id).data;
console.log(masterRecord);
},
defaultColDef: { editable: true },
onFirstDataRendered(params) {
params.api.sizeColumnsToFit();
}
Note: Master grid's rowIds are defined with [getRowNodeId]="getRowNodeId" assuming that account is the primary key of the parent grid.
A very reliable solution is to create your own detailCellRenderer.
on the init method:
this.masterNode = params.node.parent;
when creating the detail grid:
detailGridOptions = {
...
onCellClicked: params => console.log(this.masterNode.data)
}
Here is a plunker demonstrating this:
https://next.plnkr.co/edit/8EIHpxQnlxsqe7EO
I struggled a lot in finding a solution to this problem without creating custom details renderer but I could not find any viable solution. So the real good solution is already answered. I am just trying to share another way to avoid creating custom renderer.
So What I did is that I changed the details data on the fly and added the field I required from the parent.
getDetailRowData: function (params: any) {
params?.data?.children?.forEach((child:any) => {
//You can assign any other parameter.
child.parentId= params?.data?.id;
});
params.successCallback(params?.data?.children);
}
When you expand the row to render details the method getDetailRowData gets called, so it takes in params as the current row for which we are expanding the details and the details table is set by invoking params.successCallback. So before setting the row data I am iterating and updating the parentId.

ag-grid programmatically selecting row does not highlight

Using Angular 4 (typescript), I have some code like below using ag-grid 12.0.2. All I'm trying to do is load my grid and automatically (programmatically) select the first row.
:
this.gridOptions = ....
suppressCellSelection = true;
rowSelection = 'single'
:
loadRowData() {
this.rowData = [];
// build the row data array...
this.gridOptions.api.setRowData(this.rowData);
let node = this.gridOptions.api.getRowNode(...);
// console logging here shows node holds the intended row
node.setSelected(true);
// console logging here shows node.selected == true
// None of these succeeded in highlighting the first row
this.gridOptions.api.redrawRows({ rowNodes: [node] });
this.gridOptions.api.redrawRows();
this.gridOptions.api.refreshCells({ rowNodes: [node], force: true });
First node is selected but the row refuses to highlight in the grid. Otherwise, row selection by mouse works just fine. This code pattern is identical to the sample code here: https://www.ag-grid.com/javascript-grid-refresh/#gsc.tab=0 but it does not work.
Sorry I am not allowed to post the actual code.
The onGridReady means the grid is ready but the data is not.
Use the onFirstDataRendered method:
<ag-grid-angular (firstDataRendered)="onFirstDataRendered($event)">
</ag-grid-angular>
onFirstDataRendered(params) {
this.gridApi.getDisplayedRowAtIndex(0).setSelected(true);
}
This will automatically select the top row in the grid.
I had a similar issue, and came to the conclusion that onGridReady() was called before the rows were loaded. Just because the grid is ready doesn't mean your rows are ready.(I'm using ag-grid community version 19) The solution is to setup your api event handlers after your data has loaded. For demonstration purposes, I'll use a simple setTimeout(), to ensure some duration of time has passed before I interact with the grid. In real life you'll want to use some callback that gets fired when your data is loaded.
My requirement was that the handler resizes the grid on window resize (not relevant to you), and that clicking or navigating to a cell highlights the entire row (relevant to you), and I also noticed that the row associated with the selected cell was not being highlighted.
setUpGridHandlers({api}){
setTimeout(()=>{
api.sizeColumnsToFit();
window.addEventListener("resize", function() {
setTimeout(function() {
api.sizeColumnsToFit();
});
});
api.addEventListener('cellFocused',({rowIndex})=>api.getDisplayedRowAtIndex(rowIndex).setSelected(true));
},5000);
}
Since you want to select the first row on page load, you can do onething in constructor. But your gridApi, should be initialized in OnGridReady($event) method
this.gridApi.forEachNode((node) => {
if (node.rowIndex === 0) {
node.setSelected(true);
}
It's setSelected(true) that does this.
We were using MasterDetail feature, its a nested grid and on expanding a row we needed to change the selection to expanded one.
Expanding a row was handled in
detailCellRendererParams: {
getDetailRowData: loadNestedData,
detailGridOptions: #nestedDetailGridOptionsFor('child'),
}
and withing loadNesteddata, we get params using we can select expanded row as
params.node.parent.setSelected(true)
Hope this helps.

Algolia autocomplete js with select2

I am using aloglia autocomplete.js and followed the tutorial.
I want to use autocomplete text box with others select2 selectbox.
var client = algoliasearch('YourApplicationID','YourSearchOnlyAPIKey')
var index = client.initIndex('YourIndex');
autocomplete('#search-input', { hint: false }, [
{
source: autocomplete.sources.hits(index, { hitsPerPage: 5 }),
displayKey: 'my_attribute',
templates: {
suggestion: function(suggestion) {
return suggestion._highlightResult.my_attribute.value;
}
}
}
]).on('autocomplete:selected', function(event, suggestion, dataset) {
console.log(suggestion, dataset);
$("#search-input").val(suggestion.full_name.name)
});
Problem is when I clicked anywhere beside that autocomplete box autocomplete disappear and it showed only what I typed before.
I don't want it to disappear. How can I implement it? Thanks for helping.
Please see the example below for detail problem.
Assume you have a simple form with one auto complete input field,two select2 boxes and one submit button. After you choose auto complete filed, when you click anywhere, it changed to default text. I mean, you put "piz" and it shows "pizza". Therefore you select pizza and it display "pizza".Then, you try to choose one select2 box or click anywhere. The autocomplete input field changed back to "piz".
I tried autocomplete:closed , $("#search-input").focusout to set the input field but it just changed back to my query.
To prevent it from disappearing, you can use autocomplete.js's debug option:
autocomplete('#search-input', { hint: false, debug: true }, [ /* ... */ ]);
The complete options list is available on GitHub.
Now I have it. When you need to only select and not to do any action, you can safety remove autocomplete:selected. And make sure your display key is value not object.
It saves me for trouble.

Hiding UI element from fragment.xml in standard App

I want to hide few UI elements from My Travel and Expense (Standard App). I have tried in different approaches but I am not able to achieve what i want. Here is my requirement:
In My Travel and Expense App (TRV_TE_CRE), I want to hide the following UI elements:
GenericClaim.fragment.xml - Button id="costAssignmentButton"
I have added the extension project for TRV_TE_CRE and tried as below:
In component.js I added the following statement to hide
customizing:
{
"sap.ui.viewModifications": {
"mytravelandexpense.view.GenericClaim": {
"costAssignmentButton": {
"visible": false
},
},
},
Result: not working
Extended the GenericClaim.controller.js:
I added the below code in hookmethod
this.byFragmentId("costAssignmentButton").setVisible(false);
Result : whole claim page is not loading
By using access key I have commented the UI code in GenericClaim.fragment.xml
Result : not getting hide
Instead of the fragment ID, you can access the element ID from the view. Add this method in your view controller.
onAfterRendering : function(){
var buttonToHide = this.getView().byId("costAssignmentButton");
buttonToHide.setVisible(false);
},