React-Virtualized ScrollSync: How to set an initial scrollTop value? - react-virtualized

I'm using the react-virtualized ScrollSync component to sync the scrolling of a couple fixed headers — very similar to the example in the docs.
My question: is it possible to provide an initial scrollTop value to ScrollSync (or its children)? I realize that the better way to do this would be through use of scrollToRow on the Grid component that controls the scroll position — for what it's worth, I am using scrollToColumn for this purpose. But because, vertically, I'm only rendering one very tall cell, scrollToRow doesn't provide the fidelity needed.
I do realize that this is a slightly bastardized use of a grid component, but it all works quite nicely as a horizontal, infinitely loading scroller, while allowing me to re-use an existing component. If I could just set an initial scrollTop, I'd be golden.
Thanks.

Unfortunately this is not currently supported without a bit of a hack.
First, the reason for the hack: Scroll offsets flow in one direction with ScrollSync (main Grid to synchronized Grids). This means that even if ScrollSync accepted default left/top offsets as props- they would get overridden by the first render of the main Grid. I think this is probably the right thing to do to avoid ugliness inside of react-virtualized.
However you could work around it in application code like this if you wanted to:
class YourComponent extends Component {
render () {
// These are arbitrary
const defaultScrollLeft = 300
const defaultScrollTop = 500
return (
<ScrollSync>
{({ clientHeight, clientWidth, onScroll, scrollHeight, scrollLeft, scrollTop, scrollWidth }) => {
if (!this._initialized) {
scrollLeft = defaultScrollLeft
scrollTop = defaultScrollTop
this._initialized = true
}
return (
<div>
<Grid
{...otherSyncedGridProps}
scrollLeft={scrollLeft}
/>
<Grid
{...otherMainGridProps}
onScroll={onScroll}
scrollLeft={defaultScrollLeft}
scrollTop={defaultScrollTop}
/>
</div>
)
}}
</ScrollSync>
)
}
}

Related

How to redraw whole table after changing theme?

I'm using ag-grid 29 in React. I can change the style from Balham to Alpine on the fly. My problem: Neither the heard rows nor the data rows are then tall enough. Is it possible to accomplish this?
Here's the "before" - my table in Balham:
Here's the "after" - my table in Alpine. Please note the text overflowing the row height:
Here are the methods I call after the style change:
gridApi.refreshHeader()
gridApi.refreshCells()
gridApi.redrawRows()
gridApi.sizeColumnsToFit()
The official demo appears to destroy and recreate the entire grid when you change the theme dropdown, by passing a new React key to the grid component:
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const theme = params.get('theme') || 'ag-theme-alpine';
setGridTheme(theme);
}, []);
<div id="myGrid" className={gridTheme}>
<AgGridReactMemo
key={gridTheme}
// ...
/>
</div>
Actual users probably won't change the theme very often, so it's likely not worth putting effort into doing this elegantly. It may be possible to fix everything by calling various functions, but I didn't look in to it.

React Navigation 6 - Padding issue

I am working with #react-navigation/native 6 and using the headerLargeTitle option.
Depending on the screen size the padding of the title is changing. I could not find solution to adjust this through the documented APIs.
Any idea?
import { createNativeStackNavigator } from '#react-navigation/native-stack';
const PortfolioStack = createNativeStackNavigator();
const PortfolioStackScreens = (): JSX.Element => {
return (
<PortfolioStack.Navigator>
<PortfolioStack.Screen
name="Portfolio"
component={PortfolioScreen}
options={{
headerLargeTitle: true,
headerShadowVisible: false,
headerLargeTitleShadowVisible: false,
}}
/>
</PortfolioStack.Navigator>
);
};
Thank you
Whether to enable header with large title which collapses to regular header on scroll.
For large title to collapse on scroll, the content of the screen should be wrapped in a scrollable view such as ScrollView or FlatList. If the scrollable area doesn't fill the screen, the large title won't collapse on scroll. You also need to specify contentInsetAdjustmentBehavior="automatic" in your ScrollView, FlatList etc.
Only supported on iOS.
Detail

Drawer Component Backdrop blocking users from interacting with page will it is open

I have a Drawer Component anchored at the bottom but I would still like to interact with the page above the drawer but either I can click out of if but the drawer closes so I tried the variants persistent and permanent both didn't work they actually made it so nothing at all happens when I click out of if. I think it has something to do with the spacing or padding above, but if anyone knows how to disable that, it would be greatly appreciated.
I solved it slightly differently, by removing the "inset" CSS property of the .MuiDrawer-modal div:
.MuiDrawer-modal {
inset: unset !important;
}
Figured out my problem, I ended us having to do some height changes to the Paper component and it seemed to work the way I wanted. You can overrided the css with makeStyles method in the #material-ui/core/styles directory. I used the classes property example
// Outside the component
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles({
drawer: {
css here ...
}
})
// Inside Component
const classes = useStyles() // the make styles returns a function and calling the useStyles returns an object with the css.
// Inside return
<Drawer
anchor="bottom"
classes={{ paper: classes.drawer }}
>
Content...
</Drawer>

react-virtualized share CellMeasurerCache for multiple Grids

I got few grids side by side, and for first of them i want to calculate row heights dynamically using CellMeasurer, how it's possible to reuse CellMeasurerCache from this grid in another (to synchronize cell heights/widths)?
jsbin example
class App extends React.Component {
constructor(props) {
super(props);
this.leftHeadersCellMeasurerCache = new CellMeasurerCache({
fixedWidth: true,
minHeight: 40
});
}
render() {
return (
<ScrollSync>
{({scrollTop, onScroll}) => (
<div className="row">
<LeftGrid
width={300}
height={500}
scrollTop={scrollTop}
cellMeasurerCache={this.leftHeadersCellMeasurerCache}
/>
<DataGrid
width={400}
height={500}
onScroll={onScroll}
rowHeight={this.leftHeadersCellMeasurerCache.rowHeight}
/>
</div>
)}
</ScrollSync>
)
}
}
PS. Unfortunately cannot use MultiGrid, data on left side is "uneven".
You can't directly share a CellMeasurerCache cache between Grids unless the content of all cells in both Grids are the same (which I doubt is ever the case).
I think you'll want to decorate the CellMeasurerCache in a similar way as MultiGrid does. Your decorator would need to decide when to pass-thru values as-is and when to add a column-offset to avoid clobbering measurements.

Xpages attach event to partial refresh of pager in Data View

In a previous post I asked how to add a bootstrap class to a Data View. The answer was to add the class to the "table.dataview" in a script block. After the table is created the class is applied and all is well.
But when I use a pager the formatting disappears. I am using a partial refresh on the pager to only refresh the data table but doing so means that the bootstrap class does not get applied to the table.
I believe I need to add an event handler that will attach to the refresh action of the dataView to add the class. However I cannot get the event handler to work.
My code for the event handler is below.
<xp:eventHandler refreshMode="partial" submit="true"
id="applyCSS" refreshId="dataView1" event="parialRefresh"
value="what" loaded="false">
<xp:this.binding><![CDATA[#{javascript:"pager1"}]]></xp:this.binding>
<xp:this.action><![CDATA[#{javascript:("table.dataview").addClass("table-striped table-hover table-bordered table-condensed")}]]></xp:this.action>
</xp:eventHandler>
Oliver, the rendered=false was simply a typo - I was testing something and needed to temporarily suppress that.
Oliver and Paul,
Last night I was able to get the partial refresh to work.
I ran across this post by Mark Roden which explained how to do it. There were two different ways to accomplish this, one less and one more efficient. The code I used is below.
<xp:scriptBlock id="scriptBlock3">
<xp:this.value><![CDATA[$('.dataView1PanelWrapper').on("DOMNodeInserted", function(){
$("table.dataview").addClass("table-striped table-hover table-bordered table-condensed")
})]]></xp:this.value>
</xp:scriptBlock>
However, and isn't there almost always a however in Xpages, I have some sortable columns in the view and clicking on the sort brings up the same problem! I lose the class assignment!
So now I would have to intercept that event too, right?
Concerned where this will end. Don't like the idea of DOM Manipulation, and only want to do it if I have too.
I started by using a simple view. It worked great, but for some reason the spacing was messed up in the pagers. I found that by moving the pagers out of the view itself, I was able to get the alignment issue fixed. I think it would be better just to use a view, as I can assign the class directly and won't have to do all this manipulation. It is however very good to know how to do this for the future.
Is that what you would suggest?
==================================================
I have tried Paul Withers suggestion using an output script. This works on the initial page load, but not on any other changes to the data view - when the pager fires, or sorting or any of that. I am close, but no cigar yet. Any suggestions?
<xp:scriptBlock id="scriptBlock5" loaded="false">
<xp:this.value><![CDATA[dojo.require("dojo.behavior");
Behavior = {
".dataview": {
found: function(node) {
dojo.addClass(node,".table-striped table-hover table-bordered table-condensed");
//node.addClass("table-striped table-hover table-bordered table-condensed");
}
}
}
dojo.ready(function() {
dojo.behavior.add(Behavior);
dojo.behavior.apply();
});
//Make sure that future pagers are also straightened out
dojo.subscribe("partialrefresh-complete", null, function(method, form, refreshId) {
dojo.behavior.apply();
});]]></xp:this.value>
</xp:scriptBlock>
Move your existing xp:scriptBlock with the working code inside a facet of the xe:dataView. Then the styling will get applied on initial load and on all partial refreshes.
You should call your CSJS stuff to add the class in the onComplete property of the event handler - hard to find, just highlight the event handler object in source code or outline and then open "All properties" to find the "onComplete" property. This event allows CSJS to be called.
BTW: why is the loaded property = false? The event will never we rendered.
dojo.behavior, dojo.ready and dojo.subscribe should allow you to manage this. dojo.behavior allows you to define a particular behaviour for a particular collection of elements which will be retrieved via a Dojo query. dojo.ready will (I believe) run the code when the page initially loads and dojo.subscribe("partialrefresh-complete", null, function(method, form, refreshId) {...} will run the code aftedr a partial refresh.
Here's sample code I used for converting a DataView's category column images to Font Awesome icons, so the Behavior = {...} bit will need amending.
Behavior = {
// Convert xp:pagers to Bootstrap
".catColumn a img": {
found: function(img_node) {
var imgSrc = dojo.getNodeProp(img_node, "alt").toLowerCase();
if (imgSrc.indexOf("collapse") >= 0) {
dojo.place('<i class="fa fa-minus-square"></i> ', img_node, 'replace');
} else {
dojo.place('<i class="fa fa-plus-square"></i> ', img_node, 'replace');
}
}
}
}
dojo.ready(function() {
dojo.behavior.add(Behavior);
dojo.behavior.apply();
});
//Make sure that future pagers are also straightened out
dojo.subscribe("partialrefresh-complete", null, function(method, form, refreshId) {
dojo.behavior.apply();
});

Resources