AG-Grid: Consistently auto-size columns on scroll? - ag-grid

I have a large grid and would like it to dynamically resize the visible (they are virtualized) columns on horizontal scroll, but I can't seem to make it consistent since it tries to resize before the grid is fully rendered or something...
const App = () => {
const gridOptions = useMemo<GridOptions>(
() => ({
suppressColumnVirtualisation: false,
suppressRowVirtualisation: false,
processRowPostCreate: (params: ProcessRowParams) => {
console.log('processRowPostCreate');
const cols = [];
params.columnApi
.getAllDisplayedVirtualColumns()
.forEach((col) => cols.push(col));
params.columnApi.autoSizeColumns(cols, false);
},
}),
[]
);
const data = useMemo<any[]>(() => {
console.log('Create random data');
return createRandomGridData(100, 200, { resizable: true });
}, []);
const onVirtualColumnsChanged = (event: VirtualColumnsChangedEvent) => {
console.log('onVirtualColumnsChanged');
const cols = [];
event.columnApi
.getAllDisplayedVirtualColumns()
.forEach((col) => cols.push(col));
event.columnApi.autoSizeColumns(cols, false);
};
return (
<div className="ag-theme-alpine" style={{ height: '98vh', width: '98vw' }}>
<AgGridReact
gridOptions={gridOptions}
rowData={data[0]}
columnDefs={data[1]}
enableRangeSelection={true}
enableFillHandle={true}
suppressClearOnFillReduction={true}
onVirtualColumnsChanged={onVirtualColumnsChanged}
/>
</div>
);
};
Here is a live StackBlitz example: https://stackblitz.com/edit/react-ts-dwx6h7?file=App.tsx. The problem is that the grid is not auto-sized on start and when I scroll really fast it doesn't keep up.
What can I do to make it auto-size the columns more consistently?

Related

How to get current index of Story view in flutter

Im using list of images in story view in flutter, i want to get index of the list which is being displayed on the screen.
This is my code
StoryView(
storyItems: images
.map((e) => StoryItem.pageImage(
url: e,
// caption: "",
controller: newController,
))
.toList(),
onStoryShow: (s) {},
onComplete: () {
print("Completed a cycle");
Navigator.pop(context);
},
onVerticalSwipeComplete: (direction) {
if (direction == Direction.down) {
Navigator.pop(context);
}
},
progressPosition: ProgressPosition.top,
repeat: false,
controller: storyController,
),
You can do .asMap() to the list to change the list item to entry, which has the index.
const arr = ['a', 'b', 'c'];
arr.asMap().entries.map((entry) {
int index = entry.key;
String val = entry.value;
return entry;
});
all I could think of was this
Add the key to StoryItem view Image
Then in the onStoryShow add this
view Image
Finally send to server the var "storyId"

Function to return string in css property MUI v5 styled()

I'm using MUI v5's styled() and want to return a different color based on two props of the component (darkMode and destructive).
Here's what I'm doing:
const StyledButton = styled(Button)<ButtonProps>(({ darkMode, destructive }) => ({
'&.MuiButton-contained': {
backgroundColor: () => {
if (!darkMode) return 'purple';
else return 'red';
},
'&:hover': {
backgroundColor: colors.standardHoverColor
},
'&:focus': {
backgroundColor: colors.standardFocusColor
}
},
}));
I want the backgroundColor to be purple if darkMode is off, and red if it's on. There's other configurations based on destructive too, but this is a POC.
Any ideas how I can accomplish this dynamic styling based on the two props?
Thanks in advance.

Having issue while changing values in pie chart flutter

I tried this code and its working fine for the first time.
double a = 2, b = 3, c = 5;
var color;
Map<String, double> dataMap = Map();
List<Color> colorList = [
Colors.red,
Colors.green,
Colors.yellow,
];
void changeGraph() {
dataMap.putIfAbsent("Fat", () => c);
dataMap.putIfAbsent("Protein", () => b);
dataMap.putIfAbsent("Carbs", () => a);
}
void initState() {
super.initState();
changeGraph();
}
and
PieChart(
dataMap: dataMap,
animationDuration: Duration(milliseconds: 800),
chartLegendSpacing: 32.0,
chartRadius: MediaQuery.of(context).size.width / 2.7,
showChartValuesInPercentage: true,
showChartValues: true,
showChartValuesOutside: false,
chartValueBackgroundColor: Colors.grey[200],
colorList: colorList,
showLegends: true,
legendPosition: LegendPosition.right,
decimalPlaces: 1,
showChartValueLabel: true,
initialAngle: 0,
chartValueStyle: defaultChartValueStyle.copyWith(
color: Colors.blueGrey[900].withOpacity(0.9),
),
chartType: ChartType.disc,
)
then after getting values from user i tried this method for changing the graph
setState(() {
a = newA;
b = newB;
c = newC;
});
also i try to call changeGraph() method but the graph is not changing and its showing the value that it shows first time.
Is there any way to change the values ?
What your'e doing here is changing the values of the variables only and not the values inside the map.The map has the value of a = 2 and not a reference to a.
Meaning that when you say dataMap.putIfAbsent("Carbs", () => a); the value of "Carbs" is not a but it's actually 2 since the value here is an int and not a reference.
In order to change the value of Carbs in the map you need to directly change it from the map itself by doing for example datamap["Carbs"] = newA. Same goes to b and c
Let me know if that doesn't work

Flutter/Dart pattern for displaying a dialog/screen with form fields

In my flutter application, I am displaying a dialog with a series of fields controlled by a JSON representation of the form. The function that controls the form widgets is outside of the dialog implementation (so that it is reusable in widgets other than dialogs).
Inspired by the jsonToForm module (https://github.com/VictorRancesCode/json_to_form) my code is as follows:
List<Widget> jsonToForm() {
List<Widget> widgetList = new List<Widget>();
for (var count = 0; count < formItems.length; count++) {
FormItem field = FormItem.fromJson( formItems[count] );
switch( field.type ) {
case FieldType.input:
case FieldType.password:
case FieldType.email:
case FieldType.numeric:
case FieldType.textarea:
widgetList.add( _buildLabel(field.title) );
widgetList.add( _buildTextField(field) );
break;
case FieldType.radiobutton:
widgetList.add( _buildLabel(field.title) );
for (var i = 0; i < field.fields.length; i++) {
widgetList.add( _buildRadioField( field, field.fields[i] ));
}
break;
case FieldType.color:
widgetList.add( _buildColorPicker(field) );
break;
case FieldType.toggle:
widgetList.add( _buildSwitch(field) );
break;
case FieldType.checkbox:
widgetList.add( _buildLabel(field.title) );
for (var i = 0; i < field.fields.length; i++) {
widgetList.add( _buildCheckbox(field, field.fields[i] ) );
}
break;
}
}
return widgetList;
}
When a form value changes, it calls _handleChanged and then passes the form field list to the parent through an event callback.
void _handleChanged( FormItem field, { FieldItem item } ) {
var fieldIndex = formItems.indexWhere( (i) => i['name'] == field.name );
if( fieldIndex != -1 ) {
// If specified, update the subitem
if( item != null ) {
var itemIndex = field.fields.indexWhere( (i) => i.title == item.title );
field.fields.replaceRange(itemIndex, itemIndex+1, [item]);
}
// Now update the state
this.setState(() {
formItems.replaceRange(fieldIndex, fieldIndex+1, [ field.toJson() ]);
});
// Notify parents
widget.onChanged(formItems);
}
}
The problem with this approach (especially for a text field), there is no onComplete event which is only fired after all text has been entered. onChanged as well as the TextEditingController approach fire as each character is typed. Yet, I don't want to have to put the dialog button in the jsonToForm routine because then it becomes no longer reusable in other (non-dialog) screens.
Also I am not fond of the form performing an onChanged callback returning until all fields when only some have been updated. By signaling on each change event, it also ends up re-building on each character that is typed (something I would also like to avoid).
What would be ideal, is to only perform a callback withing jsonToForm when all editing for all fields are complete, but without the button, there is nothing in the jsonToForm module which can signal "I'm done".
var response;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Settings"),
actions: <Widget>[
DialogButton(
child: new Text( 'Save', style: TextStyle(color: Colors.white,fontWeight: FontWeight.w600, fontSize: 16)),
color: Colors.blue,
width: 110,
onPressed: () {
var data = List<Property>();
if( response != null ) {
response.forEach((item) => data.add( Property( name: item['name'], value: item['value'],
type: AppUtils.enumFromString( PropertyType.values, item['type'], PropertyType.string ) )));
}
var lib = this.widget.item.libraryItem;
var logger = AppConfig.newLogger(lib.id, lib.valueType, properties: data);
Navigator.pop(context, logger);
})
],
),
body: SingleChildScrollView(
child: Container(
child: Column(children: <Widget>[
JsonForm(
form: json.encode(this.widget.item.formItems),
onChanged: (dynamic response) {
this.setState(() => this.response = response);
},
),
]),
),
),
);
}
Am I stuck with putting the scaffold/widget build in the jsonToForm and then replicating this widget for screens, sub-widgets, etc or is there a more elegant solution to split the form from the container?
Seems I have discovered what the issue actually is.
The problem with the jsonToForm library that I modeled my code after puts the creation of the form in the Build function rather than in the InitState function. This causes the form to be rebuilt on each change (very bad) and subsequently if you add a TextController to a TextInputField, it goes crazy.
Anyone using the jsonToForm will need to update the code.
I also don't like the fact that it creates an array of widgets instead of using a future builder approach. .... I will slay that dragon on another day....

Make simple array from database array return is not a subtype of type 'List<UserWeightsData>' error

i can successful get data from database and i try to make simple LineChart from that,
when i try to make simple array of data, o don't get any error, but when i make that with for statement i get this error:
type 'List<dynamic>' is not a subtype of type 'List<UserWeightsData>'
for example:
class UserWeightsData {
int weightNum;
int weightValue;
UserWeightsData(this.weightNum, this.weightValue);
}
...
List<charts.Series<UserWeightsData, int>> _seriesWeightsLineData;
#override
void initState() {
super.initState();
_seriesWeightsLineData = List<charts.Series<UserWeightsData, int>>();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _buildLineChart(context),
);
}
now in this method: when i uncomment this part of code
var data = [
UserWeightsData(0,20),
UserWeightsData(1,24),
UserWeightsData(2,25),
UserWeightsData(3,40),
];
and commenting for statement, my code work fine without any problem. in that i can't make this array with for statement
for statement result:
as you can see for work fine and can make this array, but in this part of code as _seriesWeightsLineData.add(charts.Series( i get error
StreamBuilder<List<UserWeightTableData>> _buildLineChart(BuildContext context) {
final database = Provider.of<UserWeightTableDao>(context);
return StreamBuilder<List<UserWeightTableData>>(
stream: database.streamStoredUserWeights(),
builder: (context, snapshot) {
final List<UserWeightTableData> weightsList = snapshot.data ?? List();
if(weightsList.isEmpty){
return Container(child:Text('no data'));
}else{
var data = [];
for (int o = 0; o < weightsList.length; o++) {
data.add(UserWeightsData(o, weightsList[o].weight));
}
/*var data = [
UserWeightsData(0,20),
UserWeightsData(1,24),
UserWeightsData(2,25),
UserWeightsData(3,40),
];*/
_seriesWeightsLineData.add(charts.Series(
data: data,
domainFn: (UserWeightsData weight, _) => weight.weightNum,
measureFn: (UserWeightsData weight, _) => weight.weightValue,
colorFn: (UserWeightsData weight, _) => charts.ColorUtil.fromDartColor(Color(0xff990099)),
id: 'weights',
labelAccessorFn: (UserWeightsData row, _) => '${row.weightValue}',
));
return Container(
height: 200.0,
padding: EdgeInsets.all(10.0),
child: charts.LineChart(
_seriesWeightsLineData,
defaultRenderer: charts.LineRendererConfig(includeArea: true, stacked: true),
animate: true,
animationDuration: Duration(milliseconds: 500),
behaviors: [new charts.PanAndZoomBehavior()],
),
);
}
},
);
}
Give data's list a type when you create it - otherwise it becomes a list of anything (List<dynamic>).
var data = <UserWeightsData>[];
Now it's a List<UserWeightsData>.