Fixed onSort bug in data_table.dart#43735
Conversation
A comparison argument always returned true and caused the DataColumn to always think the onSort parameter (which is optional) was provided even when it wasn't.
|
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie. Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
|
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed (or fixed any issues), please reply here with What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
|
@Hixie do I need any tests for a change so straightforward? cc @willlarche |
|
@googlebot I signed it! |
|
CLAs look good, thanks! ℹ️ Googlers: Go here for more info. |
|
This appears to be a nice fix for what was probably a typo; thanks! It will definitely need a test: we don't want this issue to crop up again. Also: there are some presubmit DataTable test failures. |
|
@HansMuller I've never done a pull request on a public repository so I'm unsure what the next steps are to get this approved. |
|
You’re doing a great job! Find a test file that’s already doing tests on these classes and add one specifically to check for your case that is being fixed. |
|
Also, how is this test testWidgets('DataTable column onSort test', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Material(
child: DataTable(
columns: const <DataColumn>[
DataColumn(
label: Text('Dessert'),
),
],
rows: const <DataRow>[
DataRow(
cells: <DataCell>[
DataCell(
Text('Lollipop'), // wraps
),
],
),
],
),
),
),
);
await tester.tap(find.text('Dessert'));
await tester.pump();
expect(tester.takeException(), isNull);
});testing onSort? There isn't even an onSort parameter passed so what exactly is this testing for? |
If onSort is false, we still need to assign the label to a Row widget.
|
Note: another bad ternary comparison argument is also present in this snipped of code in data_table.dart but I am unaware of its side effects. for (DataRow row in rows) {
tableRows[rowIndex].children[0] = _buildCheckbox(
color: theme.accentColor,
checked: row.selected,
onRowTap: () => row.onSelectChanged != null ? row.onSelectChanged(!row.selected) : null ,
onCheckboxChanged: row.onSelectChanged,
);
rowIndex += 1;
} |
|
@HansMuller I'm stuck here and want to get this fix implemented as soon as possible! I'm struggling on the new tests I'm supposed to create (even the existing tests don't make sense) and I need some help. |
|
@HansMuller I believe this pr is ready |
|
@andermoran the PR still doesn't include a test. I'm afraid I don't have the time to help craft one at the moment, sorry about that. |
|
Despite weeks of looking at several resources to figure out how to write flutter tests, I still can't get the hang of it. Will this bug fix ever be merged? |
|
@Hixie I’m not sure if you’re trolling me or not but I just said I’ve spent weeks looking at several resources to write flutter tests but have been unable to. Yes, I have looked at the intro page as well as many other resources. I’ve really tried my hardest to write these tests because I want this merge to happen badly but I’ve been unable to. I’ve looked at all the resources on the web about flutter testing as well as looking through flutter tests in flutter’s source code to how it was done there. At this point I’ve given up. I wish someone could at least write one test for this PR that I need so that I can work off that. |
|
If you could file a bug that describes what you tried and how the documentation failed you, that would be great. I'm sad to hear that the current documentation was inadequate to the task. |
|
Any update? |
|
@andermoran I looked into it since this is indeed an interesting PR and exposes some problems of our code coverage. I came up with a unit test as below: testWidgets('DataTable column label position - no sort', (WidgetTester tester) async {
Widget buildTable({ int sortColumnIndex, bool sortAscending = true }) {
return DataTable(
sortColumnIndex: sortColumnIndex,
sortAscending: sortAscending,
columns: <DataColumn>[
const DataColumn(
label: Expanded(child: Center(child: Text('Name'))),
tooltip: 'Name',
),
DataColumn(
label: const Expanded(child: Center(child: Text('Calories'))),
tooltip: 'Calories',
numeric: true,
onSort: (int columnIndex, bool ascending) {},
),
],
rows: const <DataRow>[
DataRow(
cells: <DataCell>[
DataCell(Text('A long desert name')),
DataCell(Text('A lot of calories')),
],
),
]
);
}
await tester.pumpWidget(MaterialApp(
home: Material(child: buildTable()),
));
final Finder nameText = find.text('Name');
expect(nameText, findsOneWidget);
final Finder nameRow = find.ancestor(of: find.text('Name'), matching: find.byType(Row)).first;
expect(tester.getCenter(nameText), equals(tester.getCenter(nameRow)));
});This test finds the text and its immediately wrapping row, and see if they have the same center, indicating that no other padding is added. This test breaks on master and passes on your PR. However, I did find a bug (unrelated to this PR) that causes the header to disappear on mouse move, which I've filed at #51152. This bug seems to occur only when the text is not wrapped in the Hopefully this is a good starting point for you! |
|
I fear @andermoran gave up due its frustration. One of team members from flutter should finalize the pull request. It has been already more than 5 months. |
Can confirm. Was frustrating to create a test. Did give up. |
| } else { | ||
| label = Row( | ||
| textDirection: numeric ? TextDirection.rtl : null, | ||
| children: <Widget>[ label ], |
There was a problem hiding this comment.
having a row with just one child seems unnecessarily expensive... is this just to make sure that you can toggle onSort without losing state in the child? I guess that makes sense...
Probably better in that case to do this as one expression, with UI-as-code.
There was a problem hiding this comment.
I see your point. I debated whether to create a whole row for just one element. I went prioritized consistency over optimization. I would have no problem if that piece of code was changed, your point is valid
|
@dkwingsmt If the original bug was alignment issues we should probably have the test toggle the sortability (have onSort be null once, then non-null) and verify that the alignment is correct in both cases. |
|
@Hixie I can test that the alignment with |
|
I would like to have datacolumn label to be still centered even if it is sorted (up or down arrow appears on the right of the centered label). It can be annoying to see centered label moves when it is sorted. |
|
@deadsoul44 It's a good proposal, but let me explain the obstacle. The current structure can roughly be presented as: tableCell = Container(
child: Row(
children: [
label, // The `label` argument of `DataColumn`
if (onSort != null) sortingArrow,
],
),
);Imagine the cell is 100px wide, the arrow being 10px wide and the text 40 px wide. You would expect that:
Apparently No. 2 wouldn't center the text in the cell with the current implementation, because the text will be at the center of the remaining space, which is [25, 65]. The root cause is that |
|
I submitted a PR that continues this one in #51667 |
|
I understand that it is hard to align with current structure. Another option can be to add a "labelAlignment" argument. Depending on developer choice, the label can be right, center or left aligned. Currently, it is already assumed as right aligned if column is numeric and left aligned otherwise. |
|
Pending reviewer for two weeks... |
|
This PR has been continued by #51667, which has been merged. |
|
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of |


Problem
A bad comparison argument on a ternary operator made it impossible for a null value to be passed into
_buildHeadingCell'sonSortparameter causing alignment problems described in the related issues referenced below.Description
Short explanation of my fix
So for the line
the comparison argument is
column.onSort != nullinstead of() => column.onSort != null. That is where the problem lies. Because theonSortparameter will either take() => column.onSort(dataColumnIndex, sortColumnIndex != dataColumnIndex || !sortAscending)or() => nulland BOTH are non-null VoidCallback functions.If you remove the
() =>from in front of the comparison argument, you fix that problem; however, you still need to return a callback function or null so change the second argument to() => column.onSort(dataColumnIndex, sortColumnIndex != dataColumnIndex || !sortAscending)so that is passes a VoidCallback function.Long explanation of my fix
Related Issues
Tests
I didn't add any tests as this is already a part of Flutter's code and is an incredibly simple fix.
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]). This will ensure a smooth and quick review process.///).flutter analyze --flutter-repo) does not report any problems on my PR.Breaking Change
Does your PR require Flutter developers to manually update their apps to accommodate your change?