Is there any way to add a menu for each row in a sticky column (in Ag-grid)?
There is no mention about such feature in the official docu, so I'm not sure whether it's even possible. I have tried couple of ways but the menu is always trapped inside the sticky column wrapper.
The only way I could make it (at least) partially working, was by setting:
.ag-body-container .ag-row {
z-index: 0;
}
.ag-ltr .ag-hacked-scroll .ag-pinned-right-cols-viewport {
overflow: visible !important;
}
but that completely ruined vertical scrolling.
var columnDefs = [
{headerName: "ID", width: 50,
valueGetter: 'node.id',
cellRenderer: 'loadingRenderer'
},
{headerName: "Athlete", field: "athlete", width: 150},
{headerName: "Age", field: "age", width: 90},
{headerName: "Country", field: "country", width: 120},
{headerName: "Year", field: "year", width: 90},
{headerName: "Date", field: "date", width: 110},
{headerName: "Sport", field: "sport", width: 210},
{headerName: "Gold", field: "gold", width: 300},
{headerName: "Silver", field: "silver", width: 400},
{headerName: "Bronze", field: "bronze", width: 200},
{headerName: "Menu", field: "", width: 100, pinned: 'right', cellRenderer: 'menuRenderer' }
];
function MenuRenderer( params ) {
}
MenuRenderer.prototype.init = function(params) {
this.eGui = document.createElement('div');
this.eGui.classList.add('menu');
var menuElement = `
<a href="#"> * </a>
<div class="menu--list">
</div>
`;
this.eGui.innerHTML = menuElement;
};
MenuRenderer.prototype.getGui = function() {
return this.eGui;
};
var gridOptions = {
components:{
loadingRenderer: function(params) {
if (params.value !== undefined) {
return params.value;
} else {
return '<img src="./loading.gif">'
}
},
'menuRenderer': MenuRenderer
},
columnDefs: columnDefs,
rowBuffer: 0,
rowModelType: 'infinite',
paginationPageSize: 100,
cacheOverflowSize: 2,
maxConcurrentDatasourceRequests: 2,
infiniteInitialRowCount: 0,
maxBlocksInCache: 2,
//embedFullWidthRows:true,
onGridReady: function (params) {
params.api.sizeColumnsToFit();
}
}
// wait for the document to be loaded, otherwise,
// ag-Grid will not find the div in the document.
document.addEventListener("DOMContentLoaded", function() {
// lookup the container we want the Grid to use
var eGridDiv = document.querySelector('#myGrid');
// create the grid passing in the div to use together with the columns & data we want to use
new agGrid.Grid(eGridDiv, gridOptions);
agGrid.simpleHttpRequest({url: 'https://raw.githubusercontent.com/ag-grid/ag-grid-docs/master/src/olympicWinners.json'}).then(function(data) {
var dataSource = {
rowCount: null, // behave as infinite scroll
getRows: function (params) {
console.log('asking for ' + params.startRow + ' to ' + params.endRow);
// At this point in your code, you would call the server, using $http if in AngularJS 1.x.
// To make the demo look real, wait for 500ms before returning
setTimeout( function() {
// take a slice of the total rows
var rowsThisPage = data.slice(params.startRow, params.endRow);
// if on or after the last page, work out the last row.
var lastRow = -1;
if (data.length <= params.endRow) {
lastRow = data.length;
}
// call the success callback
params.successCallback(rowsThisPage, lastRow);
}, 500);
}
};
gridOptions.api.setDatasource(dataSource);
});
});
/* Menu */
.menu {
z-index: 2 !important;
position: fixed;
top: 20%;
left: 50%;
}
.menu a {
text-decoration: none;
}
.menu .menu--list {
display: none;
position: absolute;
top: 0;
right: 0px;
width: 100px;
height: 50px;
border: 1px solid red;
}
.ag-body-container .ag-row {
z-index: 0;
}
.ag-ltr .ag-hacked-scroll .ag-pinned-right-cols-viewport {
overflow: visible !important;
}
.ag-pinned-right-cols-viewport .ag-row:first-child .menu--list{
display: block;
}
/* [Layout] */
.fill-height-or-more {
min-height: 100%;
display: flex;
flex-direction: column;
border: 1px solid red;
}
.fill-height-or-more > div {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.some-area > div {
padding: 1rem;
}
.some-area > div:nth-child(1) {
flex-grow:0;
background: #88cc66;
}
.some-area > div:nth-child(2) {
flex-grow: 0;
background: #ec971f;
}
.some-area > div:nth-child(3) {
position: relative;
padding: 0;
justify-content: stretch;
align-content: flex-start;;
flex-grow:1;
background: #8cbfd9;
}
.some-area > div:nth-child(4) {
flex-grow: 0;
position: absolute;
background: #ec971f;
}
.some-area > div h2 {
margin: 0 0 0.2rem 0;
}
.some-area > div p {
margin: 0;
}
.inner{ position: absolute; top: 0; bottom: 0; left: 0; right: 0; }
html, body {
padding:0;
margin: 0;
height: 100%;
overflow: hidden;
}
.ag-body-viewport {
-webkit-overflow-scrolling: touch;
}
<head>
<script src="https://unpkg.com/ag-grid/dist/ag-grid.min.js"></script>
</head>
<html>
<body>
<section class="some-area fill-height-or-more">
<div>
Header
</div>
<div>
Action bar
</div>
<div>
<div class="inner">
<div id="myGrid" style="height: 100%; width:100%; font-size: 1.4rem" class="ag-theme-fresh"></div>
</div>
</div>
</section>
</body>
</html>
To not show the menu at all, set this property to an empty array [] . In addition, you can set the attribute suppressMenu=true to the column definition to not show the menu for a particular column. The order of the menu tabs shown in the menu will match the order you specify in this array.
To put pinned rows into your grid, set pinnedTopRowData or pinnedBottomRowData in the same way as you would set normal data into rowData . After the grid is created, you can update the pinned rows by calling api. setPinnedTopRowData(rows) and setPinnedBottomRowData(rows) .
When we want to display a header tooltip, we set the headerTooltip config as a string , and that string will be displayed as the tooltip. However, when working with custom tooltips we set colDef. tooltipComponent to assign the column's tooltip component and the headerTooltip value will passed to the params object.
Pinned (or frozen, locked, or sticky) columns are columns that are visible at all time while the user scrolls the grid horizontally. They can be pinned either to the left or right side and cannot be reordered.
I would completely abandon the idea of adding the menu inside the cell.
What I would do instead is:
Something like this: This example has no error handling for brevity.
var gridMenu = function(selector) {
var instance = this;
instance.element = document.querySelector(selector);
instance.context = null; // this can be any data, depends on your project
// sender is the link from your cell
// context is your data (see above)
instance.open = function(sender, context) {
instance.context = context;
// you may even add the sender element to your context
instance.element.style.display('block');
// alternatively, you could use instance.element.classList.add('some_class_to_make_menu_visible')
// you may need to add some positioning code here (sender would contain valuable data for that)
}
instance.close = function () {
instance.context = null;
instance.element.style.display = 'none';
// or you may remove visibility class
}
// click events for menu items (if you use some Javascript processing, and the menu doesn't use simple links)
instance.menuItem1Click = function(e) {
// do whatever you wish here
instance.close();
// call this at the end of each of your menu item click event handlers
}
// ... more click event handlers for your other menu items (one for each menu item)
return instance;
}
// Create your menu item somewhere in your document ready code, or even where you initiate your grid (before initializing the grid)
var menu = new gridMenu("#my_awesome_floating_menu");
This is a sample click event of your links inside the grid:
function cellLinkClick(event) {
var context = {}; // whatever data you may want to send to the menu
menu.open(event, context);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With