I’m having an issue with dynamically loading data into a PlutoGrid.
I’m not getting any error messages.
I am making sure that the JSON data I am getting from my API is populating a list of strings that is mapped to a list of PlutoRow objects. When I statically populate a list of strings and map that to the list of PlutoRow objects, that will display in the PlutoGrid. When I step thru my code, I noticed the following:
- The Widget build() function executes first and the rowsProviders list object is empty
- The initiState() function executes next and populates the rowsProviders list object (verified)
- The Widget build() function executes again and the rowsProviders list object now has data when I set the rows property of the PlutoGrid to it. HOWEVER, this has NO EFFECT on the grid. It has it’s column headers, but it has zero rows and there is no error message.
I have provided my code below. I have stripped out everything but this PlutoGrid. This is the code I am trying to debug.
import 'dart:convert';
import 'package:http/http.dart' as http;
import "package:flutter/material.dart";
import 'package:pluto_grid/pluto_grid.dart';
const String API_URL_LLMT_PROVIDER_ROUTE = "http://127.0.0.1:5000/get_mt_providers";
void main()
{
runApp(const MyApp());
}
class MyApp extends StatelessWidget
{
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context)
{
return MaterialApp
(
title: 'LL Translate',
theme: ThemeData(primarySwatch: Colors.blue,),
home: const DetectorPage(title: 'LLTS MT Tools'),
debugShowCheckedModeBanner: true,
);
}
}
class DetectorPage extends StatefulWidget
{
const DetectorPage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<DetectorPage> createState() => _DetectorPageState();
}
class _DetectorPageState extends State<DetectorPage>
{
final List<PlutoColumn> columnsProviders = [];
List<PlutoRow> rowsProviders = [];
List<String> providers = [];
@override
void initState()
{
super.initState();
columnsProviders.addAll
(
[
PlutoColumn
(
width: 400,
backgroundColor: Colors.blue,
title: 'MT Provider',
field: 'MT Provider Tested',
type: PlutoColumnType.text(),
enableRowChecked: true,
),
PlutoColumn
(
width: 95,
backgroundColor: Colors.blue,
title: 'WER',
field: 'Leven',
type: PlutoColumnType.text(),
enableFilterMenuItem: true,
textAlign: PlutoColumnTextAlign.center,
titleTextAlign: PlutoColumnTextAlign.center,
),
PlutoColumn
(
width: 100,
backgroundColor: Colors.blue,
title: 'BLEU',
field: 'BLEU',
type: PlutoColumnType.text(),
enableFilterMenuItem: false,
textAlign: PlutoColumnTextAlign.center,
titleTextAlign: PlutoColumnTextAlign.center,
),
PlutoColumn
(
width: 120,
backgroundColor: Colors.blue,
title: 'Combined',
field: 'Combined',
type: PlutoColumnType.text(),
enableFilterMenuItem: false,
textAlign: PlutoColumnTextAlign.center,
titleTextAlign: PlutoColumnTextAlign.center,
),
]
);
loadMtProviders();
}
void loadMtProviders() async
{
// List<String> providersList = providers.cast<String>().toList();
// List<String> providers = ['Google', 'Microsoft'];
// List<String> providers = await getMtProviders();
// providers = ['Google', 'Microsoft'];
providers = await getMtProviders();
rowsProviders = providers.map((item)
{
return PlutoRow
(
cells:
{
'MT Provider Tested':
PlutoCell
(
value: item,
),
'Leven': PlutoCell(value: ''),
'BLEU': PlutoCell(value: ''),
'Combined': PlutoCell(value: ''),
},
);
}).toList();
setState(()
{
});
}
Future<List<String>> getMtProviders() async
{
var url = Uri.parse(API_URL_LLMT_PROVIDER_ROUTE);
var response = await http.get(url);
if (response.statusCode == 200)
{
var value = response.body;
var jsonResponse = jsonDecode(value);
List<String> result = jsonResponse.cast<String>();
return result;
}
else
{
print('Request failed with status: ${response.statusCode}.');
return ['0'];
}
}
@override
Widget build(BuildContext context)
{
return Scaffold
(
body: SizedBox
(
child: PlutoGrid
(
columns: columnsProviders,
rows: rowsProviders,
),
)
);
}
}
Thanks in advance.
2
Answers
As @pixel pointed out, this is about state management in flutter. An easy way to do this is by using a StateManager object. PlutoGrid actually has a PlutoGridStateManager class for this purpose.
You first define it in your PageState class:
And then when you populate the grid, you add it to the PlutoGridStateManager:
And finally, you wire up PlutoGrid events to the PlutoGridStateManager like so:
This is a simple example. You can maintain the state of your PlutoGrid by wiring up additional events here.
Just as i have assumed the issue was about the data was not getting updated.
you need to use some state management for api calls and updating UI elements on this type of issues. here in the my resolve i have used cubit. you can read some articles for it.
In short terms the cubit do some operations(which requires some finite amount of time) and emit a state which will be caught by widgets like BlocProvider, BlocListener, BlocBuilder.. and it will show some desired Widget on that
So your getMtProviders() and loadMtProviders() functions will be moved to the cubit like below:
This fetchData function will be called. and will emit FetchedData() state. Other cubit states are as below:
And your stateful class will be as:
just how i said here BlocBuilder is there, it will show the widget according to the states emitted by the cubit who’s instance we have take and passed to it as _fetchDataCubit.
Please the change api url..
hope this would help you, happy learning