You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何按对象内嵌数组格式POST提交动态表单响应

Flutter动态表单提交适配后端格式解决方案

1. 定义匹配后端格式的数据模型类

先明确对应的数据结构,避免手动拼接JSON出错:

// 单个表单响应项,对应activity_responses数组元素
class ActivityResponse {
  final String activityFieldId;
  dynamic value;

  ActivityResponse({required this.activityFieldId, this.value});

  // 转换为后端要求的JSON结构
  Map<String, dynamic> toJson() {
    return {
      'activity_field_id': activityFieldId,
      'value': value,
    };
  }
}

// 外层提交对象
class FormSubmitPayload {
  final List<ActivityResponse> activityResponses;

  FormSubmitPayload({required this.activityResponses});

  // 生成最终提交的JSON格式
  Map<String, dynamic> toJson() {
    return {
      'activity_responses': activityResponses.map((res) => res.toJson()).toList(),
    };
  }
}

2. 用页面状态管理表单输入,替代SharedPreferences

SharedPreferences适合持久化配置,动态表单输入属于页面临时状态,直接用StatefulWidget的状态管理更高效:

class DynamicFormPage extends StatefulWidget {
  // 从后端拉取的动态表单字段列表(包含activity_field_id、字段名称等信息)
  final List<dynamic> formFields;
  const DynamicFormPage({super.key, required this.formFields});

  @override
  State<DynamicFormPage> createState() => _DynamicFormPageState();
}

class _DynamicFormPageState extends State<DynamicFormPage> {
  late List<ActivityResponse> _formResponses;
  late List<TextEditingController> _inputControllers;

  @override
  void initState() {
    super.initState();
    // 初始化响应列表,与后端返回的字段一一对应
    _formResponses = widget.formFields.map((field) {
      return ActivityResponse(
        activityFieldId: field['activity_field_id'],
        value: '', // 默认空值,可根据字段类型设置初始值
      );
    }).toList();

    // 为每个字段创建输入控制器,并绑定输入更新逻辑
    _inputControllers = List.generate(widget.formFields.length, (index) {
      final controller = TextEditingController(text: _formResponses[index].value.toString());
      // 输入变化时实时更新响应对象的值
      controller.addListener(() {
        setState(() {
          _formResponses[index].value = controller.text;
        });
      });
      return controller;
    });
  }

  @override
  void dispose() {
    // 销毁控制器,避免内存泄漏
    for (var controller in _inputControllers) {
      controller.dispose();
    }
    super.dispose();
  }

  // 提交表单核心逻辑
  Future<void> _submitForm() async {
    // 构建符合要求的提交数据
    final payload = FormSubmitPayload(activityResponses: _formResponses);
    final submitJson = payload.toJson();

    // 发送POST请求到后端(替换为你的接口地址)
    try {
      final response = await http.post(
        Uri.parse('https://your-api-url/submit-form'),
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode(submitJson),
      );

      if (response.statusCode == 200) {
        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('提交成功')));
      } else {
        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('提交失败,请重试')));
      }
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('网络错误:$e')));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('动态表单')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: ListView.builder(
          itemCount: widget.formFields.length,
          itemBuilder: (context, index) {
            final field = widget.formFields[index];
            return TextField(
              controller: _inputControllers[index],
              decoration: InputDecoration(
                labelText: field['field_name'], // 显示后端返回的字段名称
                border: const OutlineInputBorder(),
              ),
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _submitForm,
        child: const Icon(Icons.send),
      ),
    );
  }
}

3. 扩展适配多类型表单字段

如果表单包含单选框、复选框等非文本输入,只需调整对应组件的状态更新逻辑:

  • 单选框:选中时直接更新_formResponses[index].value为选项值
  • 复选框:用List存储选中值,更新时替换对应的value

内容的提问来源于stack exchange,提问作者clio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 22:25:17