0

I want a very SIMPLE way of populating my DataTable dynamically and being able to refresh it when new data is added so it updates & rebuilds instantly. Using Hive boxes and in the simplest fashion possible.

I am using Hive encrypted boxes, but that does not even matter

I am posing this question with an answer below. I spent a ton of time to discover this, as I couldn't find anything else similar using Hive boxes & SIMPLE. I truly hope this helps others, I've gotten tons of help on SO as a green dev. I am quite proud that I could possibly return the favours.

I have a class with adapter hooked up & registered to Hive

import 'package:hive/hive.dart';
part 'person.g.dart';

@HiveType(typeId: 0)
class Person {
  @HiveField(0)
  final String firstName;
  @HiveField(1)
  final String lastName;
  @HiveField(2)
  final int age;
  @HiveField(3)
  final String Status;
  Person(
    this.firstName,
    this.lastName,
    this.age,
    this.status,
  );
  @override
  String toString() {
    return '{${this.firstName}, ${this.lastName}, ${this.age}, ${this.status}}';
  }
}

Saving to the hive on button press

onPressed: () {
                  final newPersonData = Person(
                    _firstName,
                    _lastName,
                    int.parse(_age),
                    _status,
                  );

                  addPerson(newPersonData);

                  var box = Hive.box(personTable);
                  for (var index in box.values) {
                    print(index);
                  }
                },

DataTable build method

  _buildDataTable() {
        return SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: DataTable(
            columns: const <DataColumn>[
              DataColumn(
                label: Text('First'),
              ),
              DataColumn(
                label: Text('Last'),
              ),
              DataColumn(
                label: Text('Age'),
              ),
              DataColumn(
                label: Text('Status'),
              ),
            ],
            rows: List<DataRow>
                                    // How to dynamically load cells in a ***SIMPLE*** manner?
                );
              },
            ),
          ),
        );
      }
RobbB
  • 1,214
  • 11
  • 39

1 Answers1

0

DataTable build method

  _buildDataTable() {
    final hiveBox = Hive.box(personTable);

    return ValueListenableBuilder(
      valueListenable: Hive.box(personTable).listenable(),
      builder: (context, personBox, _) {
        return SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: DataTable(
            columns: const <DataColumn>[
              DataColumn(
                label: Text('First'),
              ),
              DataColumn(
                label: Text('Last'),
              ),
              DataColumn(
                label: Text('Age'),
              ),
              DataColumn(
                label: Text('Status'),
              ),
            ],
            rows: List<DataRow>.generate(
              hiveBox.length,
              (index) {
                final person = hiveBox.getAt(index) as Person;
                return DataRow(
                  cells: [
                    DataCell(Text(person.firstName)),
                    DataCell(Text(person.lastName)),
                    DataCell(Text(person.age.toString())),
                    DataCell(Text(person.status))
                  ],
                );
              },
            ),
          ),
        );
      },
    );
  }

Explanation

I'll explain as much as I know about what I'm doing above.

  • ValueListenableBuilder- this method listens for additions to the Hive.box and refreshes if any new updates occur. Without this method the DataTable will not rebuild when data is added.
  • The DataRow.generate() method allows you to iterate through whatever you want to iterate through, in my case its Strings which come from my Person object which in turn come from my encrypted Hive.

Thats pretty much it! Super simple- hope this can help others :)

EDIT: it was brought to my attention that watch() should be used instead of ValueListenableBuilder() as well as an important fact that this application renders the entire chart. For my application this is okay because I'm not building with much data. Food for thought.

RobbB
  • 1,214
  • 11
  • 39
  • 1
    btw, you can also use [watch](https://pub.dev/documentation/hive/latest/hive/BoxBase/watch.html) method - in some cases `Stream` interface is better than `ValueListenable` – pskink Mar 06 '21 at 06:35
  • Hey good to know! I’m going to try it out – RobbB Mar 06 '21 at 06:38
  • 1
    seems that `listenable()` uses `watch()` under the hood: https://github.com/hivedb/hive/blob/master/hive_flutter/lib/src/box_extensions.dart#L40 – pskink Mar 06 '21 at 06:45
  • This solution is broken, and is nothing at all like ListView.builder. Put a print in a ListView.builder, and you'll see that only the needed rows for the current view (plus a few overshoot) are built. Try the same thing here, and you'll see the entire table is built, even many offscreen rows. – Randal Schwartz Mar 06 '21 at 22:55
  • 1
    You might as well have just said `rows: hiveBox.map((person) => DataRow(...)).toList()` MUCH SIMPLER. – Randal Schwartz Mar 06 '21 at 22:59
  • Randal you're right, i see that now. Like I said in the other comment I misunderstood and miss-communicated my question accurately. Thanks for the input and simpler code! For my application I am not worried about rendering the whole table because of such small amounts of data. I will update this answer to communicate that the table renders fully. – RobbB Mar 06 '21 at 23:09