i'm using AG Grid Angular to create a log view, i will add a lot of entries per second to the grid, typically this type of view's has the newest entry at the bottom, so it would be great if there is a good way where the scrolling will stick at the bottom, so i can always see the latest entry. A bonus would be, if i can manually scroll up and the scrolling will stay at this position.
Here's one way to do it:
handle rowDataChanged in your markup:
<ag-grid-angular
class="ag-dark"
[rowData]="messages"
[columnDefs]="columnDefs"
[gridOptions]="gridOptions"
(bodyScroll)="handleScroll($event)"
(rowDataChanged)="handleRowDataChanged($event)">
</ag-grid-angular>
In the handler for rowDataChanged, call ensureVisibleIndex to scroll to the last row added:
gridOptions: GridOptions = {
suppressScrollOnNewData: true,
}
handleRowDataChanged(event) {
const index = this.messages.length - 1;
this.gridOptions.api.ensureIndexVisible(index, 'bottom');
}
Demo:
https://stackblitz.com/edit/angular-ag-grid-stuck-to-bottom
In that code there is also some logic around when to keep the table scrolled to the end or not based on the scroll position.
Related
I found a great example for this approach and it works fairly well but it starts changing the opacity when the TOP of the element scrolls off the page. Unfortunately with a larger element the visibility (opacity decrease) starts way too soon. I'm trying to figure out how to start lowering the opacity when the bottom of the element is in near proximity to the top of the top of the screen so that all elements start fading at the same time in relationship to their bottom (not their top).
Any ideas on how to accommodate that with this code? I like this code in terms of being able to control speed of the opacity change as well. Maybe leveraging element height?
Thanks!!
<script type="text/javascript">
$(function() {
var documentEl = $(document),
fadeElem = $('.fade-scroll');
documentEl.on('scroll', function() {
var currScrollPos = documentEl.scrollTop();
fadeElem.each(function() {
var $this = $(this),
elemOffsetTop = $this.offset().top;
if (currScrollPos > elemOffsetTop) $this.css('opacity', 1 - (currScrollPos-elemOffsetTop)/200); /* this number effects speed of fade aka opacity reduction*/
});
});
});
</script>
I'm working on using treeData, but was wondering if it is possible to hide the text next to the chevron.
For example, can I hide the letters from the column in this table, and just show the chevron? Maybe using cell renderer?
You can do that even without using cellRenderer.
Include below styles in your component declaration.
styles: [`
::ng-deep [class^='ag-row-group-indent-'] .ag-group-value {
display: none;
}
`]
Working plunk: Ag-Grid treeData: Possible to hide text next to chevron
Figured out an easy fix within the column def:
cellRendererParams: {
innerRenderer: () => ''
}
Is it possible to change the style of a column based on whether it's pinned or not?
I'm able to change the style based on the value while the table is rendered for the first time. What I'm trying to do is change the style when the column is pinned using the mouse (drag and pin).
I'm able to figure out which column has been pinned by firing the ColumnPinnedEvent in gridOptions. I tried modifying the cellClass of the column obtained from 'event.column' but it does not get reflected on the table.
onColumnPinned(event: ColumnPinnedEvent) {
const column = event.column;
if (column) {
const columnDef = column.getColDef();
const userProvidedColDef = columnDef;
userProvidedColDef.cellStyle = event.pinned ? { color: 'white', backgroundColor: 'black' } : {};
column.setColDef(columnDef, userProvidedColDef);
}
}
You can achieve the same by just with the CSS.
Have a look at the plunk I've created: Column Pinning and styling. Add or remove any column to see the styles updated for it.
.ag-body-viewport .ag-pinned-left-cols-container .ag-row {
background-color: yellow;
}
Here .ag-body-viewport .ag-pinned-left-cols-container hierarchy is important. Just using .ag-pinned-left-cols-container .ag-row will not work as some row levels' styling of ag-grid will overwrite it.
So far this information is enough to solve your challenge, let me know in addition to this, you have some more details to provide.
I have an ag-grid set up with a series of components in place for cell rendering. When my dataset loads the vertical scroll works well but the horizontal scroll isn't obvious unless using a trackpad or horizontal scroll enabled mouse.
I would like to be able to add a scroll bar to the top of the grid as well as the automatically generated one at the bottom?
Has anyone encountered this, come up with as solution?
Thanks in advance
This question is old but I struggled with the same issue and came up with something working.
💡 The Idea
The main idea behind my solution is to...
clone AgGrid scrollbar when grid is ready
insert the cloned scrollbar on top of the grid
add event listeners on both scrollbars to keep the scroll position synchronized
use MutationObserver to observe style attribute changes on original AgGrid scrollbar element (and child) to keep the size of the cloned scrollbar synchronized
âš¡ The Code
The following code is for Angular but the concept is the same for Vanilla JS, React or Vue.
First, get a hook on gridReady event:
<ag-grid-angular
...
(gridReady)="onGridReady()">
</ag-grid-angular>
In the function associated to the event use the following code to clone the AgGrid scrollbar and keep the scrollbars synchronized:
// hold the `MutationObserver` to be disconnected when component is destroyed
private mutationObserver: MutationObserver;
onGridReady() {
// css class selectors
const headerSelector = '.ag-header';
const scrollSelector = '.ag-body-horizontal-scroll';
const scrollViewportSelector = '.ag-body-horizontal-scroll-viewport';
const scrollContainerSelector = '.ag-body-horizontal-scroll-container';
// get scrollbar elements
const scrollElement = document.querySelector(scrollSelector);
const scrollViewportElement = document.querySelector(scrollViewportSelector);
const scrollContainerElement = document.querySelector(scrollContainerSelector);
// create scrollbar clones
const cloneElement = scrollElement.cloneNode(true) as Element;
const cloneViewportElement = cloneElement.querySelector(scrollViewportSelector);
const cloneContainerElement = cloneElement.querySelector(scrollContainerSelector);
// insert scrollbar clone
const headerElement = document.querySelector(headerSelector);
headerElement.insertAdjacentElement('afterend', cloneElement);
// add event listeners to keep scroll position synchronized
scrollViewportElement.addEventListener('scroll', () => cloneViewportElement.scrollTo({ left: scrollViewportElement.scrollLeft }));
cloneViewportElement.addEventListener('scroll', () => scrollViewportElement.scrollTo({ left: cloneViewportElement.scrollLeft }));
// create a mutation observer to keep scroll size synchronized
this.mutationObserver = new MutationObserver(mutationList => {
for (const mutation of mutationList) {
switch (mutation.target) {
case scrollElement:
cloneElement.setAttribute('style', scrollElement.getAttribute('style'));
break;
case scrollViewportElement:
cloneViewportElement.setAttribute('style', scrollViewportElement.getAttribute('style'));
break;
case scrollContainerElement:
cloneContainerElement.setAttribute('style', scrollContainerElement.getAttribute('style'));
break;
}
}
});
// start observing the scroll elements for `style` attribute changes
this.mutationObserver.observe(scrollElement, { attributeFilter: ['style'], subtree: true });
}
When destroying the component, disconnect the MutationObserver to avoid memory leaks.
ngOnDestroy() {
// stop observing
this.mutationObserver.disconnect();
}
It's tricky and all based on keeping the cloned scrollbar synchronized with the original scrollbar but so far it works great for my use cases.
Good luck 😎
Update 2022
::ng-deep{
.ag-root-wrapper{
.ag-root-wrapper-body{
.ag-root{
.ag-body-horizontal-scroll{
order: 1;
}
.ag-header{
order: 2;
}
.ag-floating-top{
order: 3;
}
.ag-body-viewport{
order: 4;
}
.ag-floating-bottom{
order: 5;
}
.ag-overlay{
order: 6;
}
}
}
}
}
How to create table with scroll overflow in Material UI v1 (v1-beta currently)? In component demos in MUI documentation there is no such example.
In all of the Table examples, there is a class applied to the div containing the Table that configures horizontal scrolling. It isn't apparent unless you're viewing the documentation with a sufficiently small viewport. (see BasicTable.js):
const styles = theme => ({
paper: {
width: '100%',
marginTop: theme.spacing.unit * 3,
overflowX: 'auto',
},
});
The paper class is applied to the root element:
function BasicTable(props) {
const classes = props.classes;
return (
<Paper className={classes.paper}>
<Table>
...
If you want a vertical scroll, you'll need to specify a height and include considerations for overflow-y. If you want both horizontal and vertical scrolling, you can set overflow and both axes will be configured:
const styles = theme => ({
paper: {
height: 300,
width: '100%',
marginTop: theme.spacing.unit * 3,
overflow: 'auto',
},
});
Note: This will not fix your column headings, because it is applied to the container. This adjustment will apply scrollbars to the entire table - heading, body, footer, etc.
In order to have the table header fixed and scroll just the table body I've come up with this solution.
First I added to each of the table components the component="div" property in order to get rid of the table skeleton completely.
Then I've added to Table, TableHead, TableBody and TableCell the display: block rule to override the material rules.
TableRows will get display: flex.
TableBody will get the desired fixed (max-)height, plus overflow: auto.
Of course by using divs instead of table tags the header and body cells lose the table alignment. In my case I solved this by setting to the first cells a fixed width, same for the first cells in the header and the first cells in body (or you can go for percentages as well) plus a flex-shrink: 0.
The second cells got flex-grow: 1
Note: Material UI v1 used
Use the "stickyHeader" property on table such as <Table stickyHeader>...</Table>