Provide getter for _rows
Closed this issue · 12 comments
List<ROW> _rows;
/// allow user to extract the updated data(add/remove)
List<ROW> get rowsData => _rows;
Hi @lvyandev !
The following getters already are available:
- int get rowsLength
- bool get isRowsEmpty
- bool get isRowsNotEmpty
- ROW rowAt(int index)
I could not allow direct access to _rows
because if it is manipulated from the outside, it will impact the model.
If a method returns UnmodifiableListView(_rows)
, it can also generate bugs in your application because the _rows
is reconstructed depending on the ordering and, in the future, on the filters as well.
Maybe to make it clear that it's just the current view, the method could be something like copyCurrentRows
and it would be a copy of _rows
. Would need to be careful about performance because it would be O(N) over the _rows
on every method call. The list would also be out of date after each ordering event. Do you think it's necessary? Are current getters not enough?
Hi. I agree with your opinions! We do need to be careful about the data.
But in my situation, I don’t only display the data but also have to modify the table and then submit. I don’t know how to obtain the edited data.that’s why I need the getter here
Are you editing the values in the cell right?
To remove lines there are also methods:
- void removeRowAt(int index)
- void removeRow(ROW row)
To edit the value in the cell, just change this value in the object that represents your row. Do this inside a setState
.
But if you need to create a new collection of rows, you can replace all rows with the method: void replaceRows(Iterable<ROW> rows)
If I understand correctly, you are looking for a table with data modified in memory for later submission. As if they were two lists of rows, the originals and the edits not yet submitted.
Perhaps the easiest would be to have a nullable value in your Row object to represent the edited value (uglier if the model has too many columns). Example:
class Person {
Person(String name) : _name = name;
String _name;
String get name => _name;
String? editedName;
void submit() {
if (editedName != null) {
_name = editedName!;
editedName = null;
}
}
}
Another way, I imagine that's what you're trying, is to create a second temporary model. If so, with the existing methods you can. The annoying thing is having to store these lists outside the model.
Sorry, I'm being insistent in trying to use the existing methods because I believe that accessing _rows
will only create more problems for you.
What do you think?
The solution also depends on how you enter edit mode. Whether it is always available (TextField always visible). Whether it's a popup window to edit? etc. Since I don't know, I don't know if I'm helping or hindering.
Sorry for the late response. You have been very helpful since I found this repo! Thanks!
The edit mode could be various, TextField, Picker, Selector or any other ways based on the column.
Add a submit function in every model is kind of unrealistic. Because there could be hundreds type of business.
Taking demo for example.
class _HomePageState extends State<HomePage> {
EasyTableModel<Person>? _model;
final List<Person> rows = [
Person('Landon', 19),
Person('Sari', 22),
Person('Julian', 37),
Person('Carey', 39),
Person('Cadu', 43),
Person('Delmar', 72)
];
@override
void initState() {
super.initState();
_model = EasyTableModel<Person>(rows: rows, columns: [
EasyTableColumn(name: 'Name', stringValue: (row) => row.name),
EasyTableColumn(name: 'Age', intValue: (row) => row.age)
]);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Demo'),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(primary: Colors.white),
onPressed: () {
final Person person = Person('Added Person', 1);
// rows.add(person);
_model?.addRow(person);
},
child: const Text('Add'),
),
TextButton(
style: TextButton.styleFrom(primary: Colors.white),
onPressed: () {
print(_model?.rowsData);
},
child: const Text('Submit'),
),
],
),
body: EasyTable<Person>(_model),
);
}
}
We may add a person or rename one. If we modify the rows on page, setState(() {});
won't update the table.
So _model?.addRow(person);
is needed. But it only changes data inside the model.
Do I have to call rows.add(person);
so that I can easily access the data for submission.
I really wish to find a proper way. Since there are tons of modifications in our business.
Sorry, I messed up. You are right, setState
will not work. But there is the EasyTableModel.notifyUpdate
method that will trigger the listeners and update the table.
Exemple on submit button:
TextButton(
style: TextButton.styleFrom(primary: Colors.white),
onPressed: () {
if (_model != null) {
_updateModel(_model!);
}
},
child: const Text('Submit'),
)
void _updateModel(EasyTableModel<Person> model) {
for (int i = 0; i < model.rowsLength; i++) {
model.rowAt(i).name = 'value ' + Random().nextInt(99999).toString();
model.rowAt(i).age = Random().nextInt(99);
}
model.notifyUpdate();
}
In this approach, the Person
attributes are no longer final and there is no "uncommitted" state only in memory preserving the original values to allow the edit to be discarded.
To have this "uncommitted" state, you should have two models (_model
and _editedModel
) and handle it. Build the _editedModel
from the _model
when entering edit mode maybe. I don't know if you need it. For me, this state is the most complicated and I don't see how to solve it easily or automatically.
What do you think? A little better?
I noticed that it will be better to have a resort method. Or replace the notifyUpdate
with another that also updates the ordering with the new values.
Um, I think I might have not explained myself well.
The current function works well.
What I wanted is pretty simple, I just need to get the list data with the ‘Added Person’ when submitting.
Since all the modifications is just kept in model, I’d rather update the ‘rows’ in page(which is a time consuming job when you have hundred of table pages containing various kinds of columns) or just have a getter of _rows in model(which is not safe to use).
So you can already use the existing methods, right? Getting each row with rowAt
and rowsLength
methods. Change the values of these rows. And then, updating the table with the notifyUpdate
method to show the new values.
Or I still don't understand? Be patient because I just got back from vacation 😜
Haha, yes! I think current function for updating and displaying is working well. We just need to have a proper way to get all the modified List<ROW>
.
For now I use pluto_grid
in my project, but I found it doesn’t meet my requirements in some certain cases(like the one we are discussing).
Do you need to fetch a separated list from the model only with the modified rows, right?
I think it would be complex for the EasyTable API to provide a solution for this. In the end, it might not even help in all cases. I try to keep my packages as simple and focused as possible.
Maybe it is more specific to each application because it depends on the object that defines a row. It could have different solutions:
- Store each line in a Set at the moment the row is changed (need a equals/hashset based on id).
- A boolean flag on the row object to indicate that it has been changed (boilerplate in every setter but easily testable).
- Use
equals
to compare with another original list (keeping multiple lists can cause problems). - ?
Since this requirement is conflict with the package concept. I am closing this issue.
Thanks for your help again!