How to dynamically add datasource to DataGrid

EDIT:

I realize my main problem here is adding data to a dataSource dynamically. All simple methods are not working. This is irregardless of which package I'm using below. The API documentation does not give any idea now to do this, all examples are hardcoded. It is not very straight forward due to the introduction of the DataGridSource... Please help me clarify this :)

I am a relatively new developer and I need some help using Syncfusion DataGrid. I am using the GetX package to inject my dependancy as well as state management. When the app runs, for some reason my DataGridSource keeps running constantly. Many times a second and eats up huge amount of cpu resources. I really don't know what I'm doing wrong and need some help.

I tried a few different methods and this is my only way to get functionality working so I'm locked up on trying different injection or state management features with GetX. Also I'm using GetX because I can inject my database data without context as opposed to Provider...

Any help is much appreciated :)

```
class DataGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder(
init: Database(),
builder: (database) {
return Scaffold(
body: SafeArea(
child: SfDataGrid(
source: GridSource(database.getEventList()),
columnWidthMode: ColumnWidthMode.fill,
columns: <GridColumn>[
GridTextColumn(
columnName: 'name',
label: Container(
color: Colors.grey[800],
padding: EdgeInsets.all(8.0),
alignment: Alignment.centerLeft,
child: Text(
'Event',
style: TextStyle(color: Colors.white),
),
),
),
GridTextColumn(
columnName: 'start',
label: Container(
color: Colors.grey[800],
padding: EdgeInsets.all(8.0),
alignment: Alignment.centerLeft,
child: Text(
'Start Date',
style: TextStyle(color: Colors.white),
),
),
),
GridTextColumn(
columnName: 'duration',
label: Container(
color: Colors.grey[800],
padding: EdgeInsets.all(8.0),
alignment: Alignment.centerLeft,
child: Text(
'Event Duration',
style: TextStyle(color: Colors.white),
overflow: TextOverflow.ellipsis,
),
),
),
GridTextColumn(
columnName: 'invitees',
label: Container(
color: Colors.grey[800],
padding: EdgeInsets.all(8.0),
alignment: Alignment.centerLeft,
child: Text(
'Attendees',
style: TextStyle(color: Colors.white),
),
),
),
GridTextColumn(
columnName: 'location',
label: Container(
color: Colors.grey[800],
padding: EdgeInsets.all(8.0),
alignment: Alignment.centerLeft,
child: Text(
'Location',
style: TextStyle(color: Colors.white),
),
),
),
],
),
),
);
});
}
}

class GridSource extends DataGridSource {
GridSource(this._eventGrid) {
print('Run');                                        /// This line is printing many times per second which shows what is running
buildDataGridRows();
}

void buildDataGridRows() {
_eventGridRow = _eventGrid
.map<DataGridRow>(
(event) => DataGridRow(
cells: [
DataGridCell<String>(columnName: 'name', value: event.eventName),
DataGridCell<String>(columnName: 'start', value: event.eventStart.toString()),
DataGridCell<String>(columnName: 'duration', value: event.eventDuration.toString()),
DataGridCell<String>(columnName: 'invitees', value: event.numberInvitees.toString()),
DataGridCell<String>(columnName: 'location', value: event.location),
],
),
)
.toList();
}

List<DataGridRow> _eventGridRow = [];
List<Event> _eventGrid = [];

@override
List<DataGridRow> get rows => _eventGridRow;

@override
DataGridRowAdapter buildRow(DataGridRow row) {
final int index = _eventGridRow.indexOf(row);
Color getRowBackgroundColor() {
if (index % 2 == 0) {
return Colors.grey[100];
}
return Colors.transparent;
}

return DataGridRowAdapter(
color: getRowBackgroundColor(),
cells: [
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.all(8.0),
child: Text(
row.getCells()[0].value,
overflow: TextOverflow.ellipsis,
),
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.all(8.0),
child: Text(
row.getCells()[1].value,
overflow: TextOverflow.ellipsis,
),
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.all(8.0),
child: Text(
row.getCells()[2].value,
overflow: TextOverflow.ellipsis,
),
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.all(8.0),
child: Text(
row.getCells()[3].value,
overflow: TextOverflow.ellipsis,
),
),
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.all(8.0),
child: Text(
row.getCells()[4].value,
overflow: TextOverflow.ellipsis,
),
),
],
);
}
}
```

Database methods used:

```
///
///
/// Read Event
/// Sends events in database to list repository
void getEvents() async {
var box = await Hive.openBox<Event>(_boxName);
eventList = box.values.toList();
refresh();
}

///
///
/// Read Event
/// Returns event list
List<Event> getEventList() {
getEvents();
return eventList;
}
```

10 Replies 1 reply marked as answer

NK Neelakandan Kannan Syncfusion Team April 21, 2021 06:40 PM UTC

 Hi Roberto,

Greetings from Syncfusion.

We have checked your code snippet and your requirement. Since DataGrid generates the rows based on the DataGridSource class’s rows property, You have to either add the new DataGridRow based on your data to rows collection or regenerate the rows collection based on currently modified collection (event collection in your case) and call the notifyListeners method. Based on your code snippet, we are providing the prototype code to add data and refresh the datagrid.

class GridSource extends DataGridSource {

GridSource(this._eventGrid) {

buildDataGridRows();

 

  void addDataGridRow(Event event) {

    rows.add(DataGridRow(cells: [

      DataGridCell<int>(columnName: 'name', value: event.eventName),

      DataGridCell<String>(columnName: 'start', value: event.eventStart.toString()),

      DataGridCell<String>(columnName: 'duration', value: event.eventDuration.toString()),

      DataGridCell<int>(columnName: 'invitees', value: event.numberInvitees.toString()),

      DataGridCell<int>(columnName: ‘location', value: event.location),

 

    ]));

 

    // To refresh the DataGrid based on CRUD operation.

    notifyListeners();

  }

}


//For example, if we add new data when click button within build method,

                TextButton(

                onPressed: () {

// You need to maintain GridSource as field

                  gridSource.addDataGridRow(

                                  Event(‘Sample’, ‘9:00 AM’, '15 mins',’2’,’Sample’));

                },

                child: Text('Add new row'))

 


If you still have doubt, can you share your simple project to us? We will look and provide the solution ASAP.

Regards,

Neelakandan



RO Roberto April 21, 2021 08:39 PM UTC

Hi Neelakandan,

I'm not too sure how to apply you'r code but I'm working on it.

I have uploaded my small project to GihHub. I'm sure it's easier to see my problem this way.

Link to project and dataGrid:
https://github.com/SexyBeast007/getx_hive_demo_one/blob/main/getx_hive_demo_one/lib/presentation/event_list_screen/data_grid.dart


RS Renugadevi Sadagoban Syncfusion Team April 22, 2021 05:41 PM UTC

Hi Roberto 
Thanks for your update.  
 
We have modified the sample to add a new row to DataGrid. We have maintained the gridSource field in event_list_screen.dart itself and passed the created gridSource to DataGrid and AddEventButton widgets. When you tap the add button, you can add data to database as well as gridSource’s eventGrid and regenerate the collection of DataGridRow based on newly added event. Finally you can call the notifyListeners method. 
 
Please refer the following code snippet, 
 
void _addEvent() { 
    final Database database = Get.put(Database()); 
    database.addEvent(Event( 
      eventName, 
      eventStart, 
      eventDuration, 
      attendees, 
      location, 
    )); 
    gridSource.eventGrid.add(Event( 
      eventName, 
      eventStart, 
      eventDuration, 
      attendees, 
      location, 
    )); 
 
    Get.back(); 
    eventDuration = DateTime.now(); 
    eventStart = DateTime.now(); 
    gridSource.buildDataGridRows(); 
    gridSource.updateDataGridSource(); 
  } 
 
 
 
 
 
We have modified your sample for your reference, 
 
Please let us know if you require any further assistance on this. 
 
 
Regards, 
Renuga devi S 
 



RO Roberto April 23, 2021 03:34 AM UTC

Renuga,

Initially I thought this solved all my problems however now I can't get the DataGrid to load any data. All that works now is adding to the grid. As soon as i navigate away and then back to the grid theres no data. Im close to giving up on this package :(((

This is a very very easy thing for me to do with DataTable. Only problem is DataGrid has so much more functionality.

Look how easy this is, why can't DataGrid have this building option? It's so simple and neat.

```
class EventDataTable extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<IncomeData>(builder: (context, eventData, child) {
return DataTable(
headingTextStyle: TextStyle(color: Colors.white),
headingRowColor:
MaterialStateColor.resolveWith((states) => Colors.green),
columns: const <DataColumn>[
DataColumn(
label: Visibility(
child: Icon(Icons.edit_rounded),
visible: false,
),
),
DataColumn(label: Text('Event')),
DataColumn(label: Text('Date')),
DataColumn(label: Text('Event Duration')),
DataColumn(label: Text('Attendees')),
DataColumn(label: Text('Location')),
],
rows: List<DataRow>.generate(
Provider.of<Event>(context).eventCount,
(index) {
Event currentEvent = eventData.getEvent(index);

return DataRow(
color: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) => (index % 2 == 0)
? Colors.green.shade100
: Colors.green.shade50),
cells: [
DataCell(Icon(Icons.edit_rounded)),
DataCell(Text(currentEvent.eventName)),
                DataCell(Text(DateFormat.yMMMd().format(currentEvent.eventDate))),
DataCell(Text(DateFormat.yMMMd().format(currentEvent.eventDuration)))
DataCell(Text(currentEvent.attendees)),
DataCell(Text(currentEvent.location)),
],
);
},
),
);
});
}
}
```


RS Renugadevi Sadagoban Syncfusion Team April 23, 2021 05:34 PM UTC

Hi Roberto, 
  
Sorry for the inconvenience caused. 
  
Our DataGrid’s API structure is similar to PaginatedDataTable where we require the DataGridSource to process the data. As per the Get package, it provides the updated data always only by using GetBuilder. So, if you use the GetBuilder and pass the DataGridSource to DataGrid, its properly displaying the data when you back to DataGrid page. Please find the code snippet in below, 
  
class EventListScreen extends StatelessWidget { 
  GridSource dataSource; 
  final Database database = Get.put(Database()); 
  
  @override 
  Widget build(BuildContext context) { 
    return GetBuilder<Database>(builder: (database) { 
      dataSource = GridSource(database.getEventList()); 
      return Scaffold( 
          appBar: AppBar( 
            title: Text('Event Dashboard'), 
            backgroundColor: Colors.grey[850], 
            actions: [AddEventButton(source: dataSource)], 
          ), 
          body: DataGrid( 
            source: dataSource, 
          )); 
    }); 
  } 
} 
 
  
Please let us know if you have any concerns in this. 
 
Regards,
Renuga devi S
 



RO Roberto April 24, 2021 10:53 PM UTC

Hi Renuga,

I applied what you last posted, the problem is this brings me back to the last problem where the Getbuilder runs continuously. I put a print statement into the GridSource constructor to be able to spot this and it runs about 50 times per second and eats up huge resources. This is my problem, I still can't add data dynamically.


RS Renugadevi Sadagoban Syncfusion Team April 26, 2021 12:35 PM UTC

Hi Roberto, 
 
Thanks for your update.  
  
We are currently analyzing your requirement. We will validate and update you the details in two business days (April 28, 2021). We appreciate your patience until then.  
 
Regards, 
Renuga devi S 



RS Renugadevi Sadagoban Syncfusion Team April 28, 2021 11:26 AM UTC

Hi Roberto,

Thanks for your patience.
 
  
As you updated, GetBuilder will be called 50 times for every seconds. Due to GridSource (event list is generated from DataBase) object 50 times per seconds, CPU usage is high. To avoid this, you can use the single object of GridSource and assign that to SfDataGrid. You can listen the CRUD operation performed in DataBase by adding the listener to DataBase. So, you can refresh and generate the DataGridRows whenever CRUD operation is performed in DataBase. Please find the code snippet in below, 
  
event_list_screen.dart 
class EventListScreen extends StatelessWidget { 
  EventListScreen() { 
    database = Get.put(Database()); 
    dataGridSource = GridSource(database: database); 
  } 
  
  Database database; 
  
  // Holds the data source for the DataGrid. 
  GridSource dataGridSource; 
  
  @override 
  Widget build(BuildContext context) { 
    return GetBuilder<Database>( 
      builder: (database) { 
        return Scaffold( 
          appBar: AppBar( 
            title: Text('Event Dashboard'), 
            backgroundColor: Colors.grey[850], 
            actions: [AddEventButton(source: dataGridSource)], 
          ), 
          body: DataGrid(source: dataGridSource), 
        ); 
      }, 
    ); 
  } 
} 
  
data_grid.dart 
  
  final GridSource source; 
  
  @override 
  Widget build(BuildContext context) { 
    return Scaffold( 
      body: SafeArea( 
        child: GetBuilder<Database>( 
          builder: (database) { 
            return SfDataGrid( 
              source: source, 
              columnWidthMode: ColumnWidthMode.fill, 
               …… 
  
class GridSource extends DataGridSource { 
  GridSource({this.database}) { 
    // Build initial data grid rows. 
    initialLoading(); 
    database.addListener(handleListUpdates); 
    print('Run'); 
  } 
  
  Database database; 
  
  List<Event> eventList = []; 
  
  List<DataGridRow> _eventGridRow = []; 
  
  void initialLoading() { 
    eventList = database.getEventList(); 
    buildDataGridRows(); 
  } 
  
// This will refresh the DataGrid when you add the new rows to DataBase. 
void handleListUpdates() { 
    eventList = database.eventList; 
    buildDataGridRows(); 
    notifyListeners(); 
  } 
……….. 
  
  
  
We have modified your sample for your reference, 
  
  
 
Regards, 
Renuga devi S 


Marked as answer

RO Roberto April 30, 2021 12:29 AM UTC

Hi Renuga,

This fixes it all and adds dynamic data! Thank you very much for the help :) I appreciate the help from Syncfusion.


RS Renugadevi Sadagoban Syncfusion Team April 30, 2021 06:08 AM UTC

Hi Roberto, 
Thanks for your update. 

We are glad to know that our solution meets your requirement. Please get back to us if you require any further assistance. We will be happy to assist you. 
  
Regards, 
Renuga devi S 


Loader.
Up arrow icon