Skip to content

feat(picker): support dynamic column data loading via onColumnChanged…#910

Open
Luozf12345 wants to merge 2 commits into
developfrom
feat/issue-817-picker-dynamic-data
Open

feat(picker): support dynamic column data loading via onColumnChanged…#910
Luozf12345 wants to merge 2 commits into
developfrom
feat/issue-817-picker-dynamic-data

Conversation

@Luozf12345
Copy link
Copy Markdown
Collaborator

🤔 这个 PR 的性质是?

勾选规则:
1.只要有新增参数,就勾选”新特性提交“
2.只修改内部bug,未新增参数,才勾选”日常 bug 修复“
3.其他选项视具体改动判断

  • 日常 bug 修复
  • 新特性提交
  • 文档改进
  • 演示代码改进
  • 组件样式/交互改进
  • CI/CD 改进
  • 重构
  • 代码风格优化
  • 测试用例
  • 分支合并
  • 其他

🔗 相关 Issue

💡 需求背景和解决方案

📝 更新日志

修复TDPicker的initialData更新异常。

  • fix(组件名称): 处理问题或特性描述 ...

  • 本条 PR 不需要纳入 Changelog

☑️ 请求合并前的自查清单

⚠️ 请自检并全部勾选全部选项⚠️

  • pr目标分支为develop分支,请勿直接往main分支合并
  • 标题格式为:组件类名: 修改描述(示例:TBottomTabBar: 修复iconText模式,底部溢出2.5像素)
  • ”相关issue“处带上修复的issue链接
  • 相关文档已补充或无须补充

Luozf12345 and others added 2 commits April 10, 2026 17:59
…fixes #817)

- Add `LinkedPickerColumnChangedCallback` typedef for async column data loading
- Add `onColumnChanged` param to `TMultiLinkedPicker` and `TPicker.showMultiLinkedPicker`
- Add `isLoading` state to `MultiLinkedPickerModel` for per-column loading indicator
- Add `resetColumnsAfter`, `updateColumnData`, `setLoading` methods to model
- Add `cascadeNext` param to `refreshPresentDataAndController` for external data control
- Show loading indicator in column while async data is being fetched
- Fully backward compatible: existing behavior unchanged when `onColumnChanged` is null
- Add demo example with 300ms simulated network delay
- Add 14 unit tests covering all scenarios (TC-01 to TC-06 + BC-02)
- Regenerate picker_api.md with new API docs

Made-with: Cursor
@tencent-adm
Copy link
Copy Markdown
Member

CLA assistant check
Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ Luozf12345
❌ autofix-ci[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions
Copy link
Copy Markdown
Contributor

完成

📱 APK 下载

tdesign-flutter-0.2.7-445.apk

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new onColumnChanged callback to TMultiLinkedPicker/TPicker.showMultiLinkedPicker to support dynamically loading the next column’s data (async), updates the related docs/demo, and adds unit tests around the linked picker model behavior.

Changes:

  • Add LinkedPickerColumnChangedCallback and wire it through TPicker.showMultiLinkedPickerTMultiLinkedPicker.
  • Implement async next-column loading with a loading placeholder and new model helpers (resetColumnsAfter, updateColumnData, isLoading).
  • Update site/API docs and add picker model tests + a demo for dynamic loading.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tdesign-site/src/picker/README.md Documents new onColumnChanged parameter and updates API signature table.
tdesign-site/src/date-time-picker/README.md Updates showMultiLinkedPicker signature docs to include onColumnChanged.
tdesign-component/lib/src/components/picker/t_picker.dart Adds onColumnChanged parameter and passes it into TMultiLinkedPicker.
tdesign-component/lib/src/components/picker/t_multi_picker.dart Implements dynamic linked loading flow, loading UI, and model support (isLoading, reset/update helpers, cascade control).
tdesign-component/test/td_picker_test.dart Adds unit tests for MultiLinkedPickerModel new behaviors.
tdesign-component/example/lib/page/t_picker_page.dart Adds demo and mock async loader for onColumnChanged.
tdesign-component/example/assets/code/picker.buildDynamicLinkedPicker.txt Adds demo code snippet asset for the new example.
tdesign-component/example/assets/api/picker_api.md Updates generated API docs with onColumnChanged.
tdesign-component/example/assets/api/date-time-picker_api.md Updates generated API docs with onColumnChanged in signature table.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +474 to +482
// data 传空 Map,完全由 onColumnChanged 提供数据
data: {
'广东省': {},
'浙江省': {},
},
columnNum: 3,
initialData: ['广东省', '', ''],
onColumnChanged: _fetchNextColumnData,
);
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

示例里把 data 的下一层设为 {}(空 Map),但当前 MultiLinkedPickerModel 初始化第 1/2 列时会从 Map keys 取数据;空 keys 会导致该列数据为空,从而在创建 FixedExtentScrollController 时出现空数据列的异常/不可用。建议示例中至少提供占位数据(例如 [''])或调整组件实现:当下一层为空时回退到 placeData,并可在 initState 根据 initialData 主动触发 onColumnChanged 预加载下一列。

Copilot uses AI. Check for mistakes.
Comment on lines +228 to +237
// BC-02:最后一列变化时不应触发加载(无下一列)
test('最后一列无需加载下一列数据', () {
final model = MultiLinkedPickerModel(
data: testData,
columnNum: 3,
initialData: ['广东省', '深圳市', '南山区'],
);
// 最后一列 columnIndex = 2 = columnNum - 1,不应触发下一列更新
expect(2 >= model.columnNum - 1, isTrue);
});
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

该用例只验证了一个恒为真的不等式(2 >= columnNum - 1),没有覆盖“最后一列不会触发加载/不会调用 onColumnChanged”的实际行为,容易产生误导。建议删除该断言或替换为能验证真实行为的测试(例如在 widget 测试中监听回调调用次数)。

Suggested change
// BC-02:最后一列变化时不应触发加载(无下一列)
test('最后一列无需加载下一列数据', () {
final model = MultiLinkedPickerModel(
data: testData,
columnNum: 3,
initialData: ['广东省', '深圳市', '南山区'],
);
// 最后一列 columnIndex = 2 = columnNum - 1,不应触发下一列更新
expect(2 >= model.columnNum - 1, isTrue);
});

Copilot uses AI. Check for mistakes.
initialData: ['广东省', '深圳市', '南山区'],
);
model.updateColumnData(1, ['杭州市', '宁波市']);
expect(model.controllers[1].initialItem, 0);
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里断言 controllers[1].initialItem == 0 不能证明 updateColumnData 发生了“跳转到第 0 项”,因为 initialItem 是构造参数且不会随 jumpToItem 更新。建议改为断言 model.selectedIndexes[1] / model.selectedData[1] 被重置,或在可 attach controller 的 widget 测试里验证 selectedItem/滚动位置。

Suggested change
expect(model.controllers[1].initialItem, 0);
expect(model.selectedIndexes[1], 0);
expect(model.selectedData[1], '杭州市');

Copilot uses AI. Check for mistakes.
Comment on lines +258 to 259
| onColumnChanged | LinkedPickerColumnChangedCallback? | - | 列选项变化时的回调,用于动态加载下一列数据 |
| onConfirm | MultiPickerCallback? | - | 选择器确认按钮回调 |
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR 描述/勾选项标记为“日常 bug 修复”,但这里新增了对外 API 参数 onColumnChanged(并更新了文档/示例),属于对外能力扩展。建议同步调整 PR 类型与更新日志(以及需要的话纳入 Changelog),避免发布/版本语义混淆。

Copilot uses AI. Check for mistakes.
Comment on lines +1016 to +1027
void resetColumnsAfter(int columnIndex) {
for (var i = columnIndex + 1; i < columnNum; i++) {
while (presentData.length <= i) {
presentData.add([placeData]);
}
presentData[i] = [placeData];
currentPages[i] = 0;
hasMoreData[i] = false;
if (i < controllers.length) {
controllers[i].jumpToItem(0);
}
}
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resetColumnsAfter 只重置了 presentData/controller/hasMoreData,但没有同步重置后续列的 selectedData/selectedIndexes;当用户改变前一列并触发动态加载时,确认/回调仍可能携带旧的后续列选中值,导致结果与 UI 不一致。建议在重置后续列时同时把 selectedData[i] 置为占位值、selectedIndexes[i] 置 0。

Copilot uses AI. Check for mistakes.
Comment on lines +709 to +722
Future<void> _loadNextColumnData(int columnIndex) async {
final nextColumn = columnIndex + 1;
setState(() {
model.resetColumnsAfter(columnIndex);
model.setLoading(nextColumn, true);
});
try {
final newData =
await widget.onColumnChanged!(columnIndex, model.selectedData);
if (!mounted) return;
setState(() {
model.updateColumnData(nextColumn, newData);
model.setLoading(nextColumn, false);
});
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_loadNextColumnData 没有处理用户快速滚动导致的并发请求乱序:先发起的 onColumnChanged 可能在后发起的之后返回,从而用过期数据覆盖当前选择对应的列数据/加载状态。建议为每次请求引入递增 requestId/token,并在 await 返回后校验 token 或当前 selectedData 是否仍匹配,再决定是否 updateColumnData/setLoading。

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants