Flutter集成ASP.NET API:如何将Model转换为List实现搜索
解决Flutter与ASP.NET API集成中的搜索功能问题
首先明确核心逻辑:你的listmodel本身已经包含了要展示的数据列表rows(类型为List<Rows>),不需要把整个listmodel转换为List,搜索功能直接基于rows列表实现即可。下面针对你的代码问题给出具体修复方案:
一、修正当前代码的错误点
你在BlocBuilder中的写法存在本质错误:
state.listModel.toJson()会将模型转为Map,而非List,后续List.from(readmodel as Iterable)完全不成立readmodel.entries((element) => element.drainageid)语法错误,Map的entries返回的是键值对,不存在drainageid属性
二、方案一:局部状态实现前端过滤(简单快速)
如果搜索仅在当前页面生效,无需全局状态同步,直接用StatefulWidget的局部状态维护过滤后的数据:
1. 在State类中定义变量
class _YourPageState extends State<YourPage> { late List<Rows> _originalRows; // 保存原始数据,用于重置过滤 late List<Rows> _filteredRows; // 过滤后的数据,用于UI展示 @override Widget build(BuildContext context) { return BlocBuilder<ListBloc, ListState>( builder: (context, state) { if (state is ListInitial || state is ListLoading) { return _buildLoading(); } else if (state is ListLoaded) { // 初始化原始数据和过滤列表 _originalRows = state.listModel.rows ?? []; _filteredRows = List.from(_originalRows); // 搜索过滤方法 void updateFilter(String value) { setState(() { _filteredRows = _originalRows.where((row) { // 自定义搜索规则:匹配ID或检查人字段,忽略大小写 final idMatch = row.id?.toLowerCase().contains(value.toLowerCase()) ?? false; final inspMatch = row.inspby?.toLowerCase().contains(value.toLowerCase()) ?? false; return idMatch || inspMatch; }).toList(); }); } return Column( children: [ // 搜索输入框 TextField( onChanged: updateFilter, decoration: const InputDecoration( hintText: "搜索ID/检查人", prefixIcon: Icon(Icons.search), ), ), // 过滤后的列表 Expanded(child: _buildListView(context, _filteredRows)), ], ); } else if (state is ListError) { return const Center(child: Text("加载失败")); } else { return const SizedBox(); } }, ); } // 修改列表构建方法,接收Rows列表 Widget _buildListView(BuildContext context, List<Rows> rows) { return ListView.builder( itemCount: rows.length, itemBuilder: (context, index) { final row = rows[index]; return ListTile( title: Text(row.id ?? "无ID"), subtitle: Text(row.inspby ?? "无检查人"), trailing: Text(row.dateofinsp?.toString().split(" ").first ?? "无日期"), ); }, ); } }
三、方案二:Bloc全局状态管理搜索
如果需要多页面共享搜索状态,或者需要配合后端搜索,用Bloc事件驱动实现:
1. 添加搜索事件
abstract class ListEvent {} class FetchListEvent extends ListEvent {} class SearchListEvent extends ListEvent { final String query; SearchListEvent(this.query); }
2. 修改Bloc状态结构
abstract class ListState {} class ListInitial extends ListState {} class ListLoading extends ListState {} class ListLoaded extends ListState { final ListModel listModel; final List<Rows>? filteredRows; ListLoaded(this.listModel, {this.filteredRows}); } class ListError extends ListState { final String error; ListError(this.error); }
3. Bloc处理搜索逻辑
class ListBloc extends Bloc<ListEvent, ListState> { final ApiRepository repository; late ListModel _originalModel; ListBloc(this.repository) : super(ListInitial()) { on<FetchListEvent>(_fetchList); on<SearchListEvent>(_handleSearch); } void _fetchList(FetchListEvent event, Emitter<ListState> emit) async { emit(ListLoading()); try { final model = await repository.fetchlistList(); _originalModel = model; emit(ListLoaded(model, filteredRows: model.rows)); } catch (e) { emit(ListError(e.toString())); } } // 前端过滤逻辑 void _handleSearch(SearchListEvent event, Emitter<ListState> emit) { final rows = _originalModel.rows ?? []; final filtered = rows.where((row) { final idMatch = row.id?.toLowerCase().contains(event.query.toLowerCase()) ?? false; final inspMatch = row.inspby?.toLowerCase().contains(event.query.toLowerCase()) ?? false; return idMatch || inspMatch; }).toList(); emit(ListLoaded(_originalModel, filteredRows: filtered)); } }
4. BlocBuilder中使用过滤后的数据
BlocBuilder<ListBloc, ListState>( builder: (context, state) { if (state is ListInitial || state is ListLoading) { return _buildLoading(); } else if (state is ListLoaded) { return Column( children: [ TextField( onChanged: (value) => context.read<ListBloc>().add(SearchListEvent(value)), decoration: const InputDecoration(hintText: "搜索ID/检查人"), ), Expanded(child: _buildListView(context, state.filteredRows ?? [])), ], ); } else { return const Center(child: Text("加载失败")); } }, )
四、后端搜索优化(可选)
如果数据量较大,前端过滤性能差,可以让ASP.NET API支持搜索参数,修改API请求逻辑:
1. 修改ApiProvider请求方法
Future<ListModel> fetchlistList({String? searchQuery}) async { try { final params = searchQuery != null ? {"search": searchQuery} : {}; final response = await _dio.get( _url, options: Options(headers: {"keyishere": "xxxxxxx"}), queryParameters: params, ); return ListModel.fromJson(response.data); } catch (error, stacktrace) { print("Exception: $error StackTrace: $stacktrace"); return ListModel.withError("数据加载失败/连接问题"); } }
2. 修改Bloc的搜索事件逻辑
void _handleSearch(SearchListEvent event, Emitter<ListState> emit) async { emit(ListLoading()); try { final model = await repository.fetchlistList(searchQuery: event.query); emit(ListLoaded(model, filteredRows: model.rows)); } catch (e) { emit(ListError(e.toString())); } }
额外规范建议
Dart命名规范要求类名首字母大写,建议修改:
listmodel→ListModellistState→ListStateRows→InspectionRow(避免和Flutter内置Row组件冲突)
内容的提问来源于stack exchange,提问作者user21497668
相关产品推荐
相关产品推荐

