阅读 725

Flutter 入门与实战(二十四):使用 Dio的 Patch请求完成详情编辑

前言

这是 Dio 网络请求的第三篇,我们将从浅到深完成 Dio 的学习,前面两篇如下:

本篇介绍表单更新请求,利用 Patch 请求更新动态数据,需要做得准备工作如下:

  • 拉取后台新的代码,项目地址:后台源码,拉到本地后,在项目目录运行 node seed.js 生成测试数据。
  • 运行后台应用:在项目目录node index.js 即可运行后台接口应用,项目默认接口地址为:http://localhost:3900/api/

整理代码

回顾一下上一篇的代码,发现上一篇的提醒错误代码和业务无关,可以抽离为一个公共的方法,方便后面在其他地方调用,新建一个 utils/dialogs.dart 文件,将错误提示方法移到里面:

import 'package:flutter/material.dart';

class Dialogs {
  static void showInfo(BuildContext context, String info) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
      content: Text(info),
    ));
  }
}

复制代码

之前我们在列表是在 initialState 方法里主动刷新请求数据的,实际上 EasyRefresh 本身提供了一个属性firstRefresh来设置首次是否自动刷新,因此我们可以移除之前的主动刷新代码,将 firstRefresh 设置为 true 即可。

编辑页面实现

首先新增一个 dynamic_edit.dart 文件,里面有三个表单和一个按钮,分别对应的是标题、内容和图片链接地址(这里我们暂时不考虑图片上传)。表单利用的是我们之前封装的通用表单组件,可以参考之前的:Flutter 入门与实战(十):封装一个通用的文本输入框。这里在没有请求到数据的时候我们显示“加载中...”,若请求成功则显示实际的表单内容,构建界面的代码如下:

_getFormWidgets() {
  if (_formData == null)
    return Center(
      child: Text('加载中...'),
    );
  return Container(
    child: Column(
      children: [
        FormUtil.textField(
          'title',
          _formData['title']['value'] ?? '',
          controller: _formData['title']['controller'] ?? null,
          hintText: '请输入标题',
          prefixIcon: Icons.title,
          onChanged: _handleTextFieldChanged,
          onClear: _handleClear,
        ),
        FormUtil.textField(
          'content',
          _formData['content']['value'] ?? '',
          controller: _formData['content']['controller'] ?? null,
          hintText: '请输入内容',
          prefixIcon: Icons.content_paste,
          onChanged: _handleTextFieldChanged,
          onClear: _handleClear,
        ),
        FormUtil.textField(
          'imageUrl',
          _formData['imageUrl']['value'] ?? '',
          controller: _formData['imageUrl']['controller'] ?? null,
          hintText: '请输入图片链接',
          prefixIcon: Icons.image,
          onChanged: _handleTextFieldChanged,
          onClear: _handleClear,
        ),
        ButtonUtil.primaryTextButton('保存', () {
          _handleSubmit();
        }, context),
      ],
    ),
  );
}
复制代码

在列表项的长按弹层中我们增加了一个编辑按钮,点击后跳转到编辑页面,具体参考源码即可。

获取详情数据

在编辑前,我们要通过 id 请求后台数据来填充表单,这里使用之前讲过的 get 请求,方法如下。若请求成功,返回状态码200时,构建表单的_formData数据,也就是表单所需要的数据,同时更新界面。如果请求失败则调用封装的信息提示方法,显示错误信息。

void _getDynamic(String id) async {
    try {
      var response = await DynamicService.get(id);
      if (response.statusCode == 200) {
        dynamicEntity = DynamicEntity.fromJson(response.data);
        setState(() {
          _formData = {
            'title': {
              'value': dynamicEntity.title,
              'controller': TextEditingController(text: dynamicEntity.title),
              'obsecure': false,
            },
            'content': {
              'value': dynamicEntity.content,
              'controller': TextEditingController(text: dynamicEntity.content),
              'obsecure': false,
            },
            'imageUrl': {
              'value': dynamicEntity.imageUrl,
              'controller': TextEditingController(text: dynamicEntity.imageUrl),
              'obsecure': false,
            },
          };
        });
      } else {
        Dialogs.showInfo(this.context, response.statusMessage);
      }
    } on DioError catch (e) {
      Dialogs.showInfo(this.context, e.message);
    } catch (e) {
      Dialogs.showInfo(this.context, e.toString());
    }
  }

复制代码

提交更新数据

在提交数据前我们需要做校验,这里为了简单起见,只是保证数据不为空即可,后续我们可以校验工具来对各个字段进行准确的校验。校验通过后,从_fromData中提取实际要提交的表单数据。

_handleSubmit() async {
  if ((_formData['title']['value'] as String).trim() == '') {
    Dialogs.showInfo(this.context, '标题不能为空');
    return;
  }

  if ((_formData['content']['value'] as String).trim() == '') {
    Dialogs.showInfo(this.context, '内容不能为空');
    return;
  }

  if ((_formData['imageUrl']['value'] as String).trim() == '') {
    Dialogs.showInfo(this.context, '图片链接不能为空');
    return;
  }

  try {
    Map<String, String> newFormData = {};
    _formData.forEach((key, value) {
      newFormData[key] = value['value'];
    });
    var response = await DynamicService.update(dynamicEntity.id, newFormData);
    if (response.statusCode == 200) {
      Dialogs.showInfo(context, '保存成功');
    } else {
      Dialogs.showInfo(this.context, response.statusMessage);
    }
  } on DioError catch (e) {
    Dialogs.showInfo(this.context, e.message);
  } catch (e) {
    Dialogs.showInfo(this.context, e.toString());
  }
}
复制代码

实际可以发现,我们的网络请求除了请求方法不同以外,其他代码几乎如出一辙,这也是后面的篇章需要统一封装的原因,要不太多重复代码了,万一哪天改起来会很痛苦。DynamicService.update接收要更新的数据的 id 和要更新的表单数据,实际就是简单调用了 Diopatch 方法。

static Future update(String id, Map<String, dynamic> data) async {
  var result = await Dio().patch(host + 'dynamics/' + id, data: data);

  return result;
}
复制代码

运行效果

编辑完成后,我们重新刷新数据,可以看到内容和图片都发生了改变(如何保存成功后自动同步列表,我们讲完添加后再一起来解决)。

屏幕录制2021-07-05 下午9.59.35.gif

(录屏有点尴尬,粘贴图片链接半天没粘贴上😹)

总结

本篇介绍了详情数据的获取,实体对象的部分修改来展示 Dio的 patch 请求。可以看到,Dio 提供的一系列 Restful 请求的方式基本相同,这样给我们统一封装留下了空间。下一篇我们介绍如何创建数据以及操作成功后如何同步更新后的数据到列表,网络相关代码源码地址为:gitee.com/island-code…

文章分类
前端
文章标签