高级表单

AdvancedForm 类为 Jinja 模板提供表单验证、CSRF 保护和渲染辅助功能。

创建表单

通过继承 AdvancedForm 并实现 fields() 方法来创建表单类:

import 'package:finch/finch_route.dart';

class RegisterForm extends AdvancedForm {
  @override
  List<FormField> fields() => [
    FormField(
      name: 'name',
      label: '全名',
      validators: [
        FormValidator.required(),
        FormValidator.minLength(2),
        FormValidator.maxLength(100),
      ],
    ),
    FormField(
      name: 'email',
      label: '电子邮箱',
      validators: [
        FormValidator.required(),
        FormValidator.email(),
      ],
    ),
    FormField(
      name: 'password',
      label: '密码',
      validators: [
        FormValidator.required(),
        FormValidator.minLength(8),
      ],
    ),
  ];
}

表单验证

Future<String> register() async {
  var form = RegisterForm();
  await form.init(rq);

  return form.check(
    onValid: () async {
      var name     = form.getValue('name');
      var email    = form.getValue('email');
      var password = form.getValue('password');

      await UserModel().create({
        'name': name,
        'email': email,
        'password': hashPassword(password),
      });

      return rq.redirect(url: '/dashboard');
    },
    onInvalid: () async {
      return rq.renderView(
        path: 'auth/register',
        params: {'form': form},
      );
    },
  );
}

验证器

验证器 描述
FormValidator.required() 字段不能为空
FormValidator.email() 必须是有效的电子邮件地址
FormValidator.minLength(n) 至少 n 个字符
FormValidator.maxLength(n) 最多 n 个字符
FormValidator.min(n) 数值 ≥ n
FormValidator.max(n) 数值 ≤ n
FormValidator.regex(pattern) 必须匹配正则表达式
FormValidator.match('other') 必须与另一个字段相等
FormValidator.custom(fn) 自定义验证函数

CSRF 保护

AdvancedForm 自动处理 CSRF 验证。在模板中添加隐藏 input:

<form method="POST">
  {{ form.csrfInput() }}
  {# ... 表单字段 ... #}
  <button type="submit">注册</button>
</form>

模板中的字段状态

form 对象提供字段状态和错误消息:

<div class="field {% if form.hasError('email') %}error{% endif %}">
  <label>{{ form.getLabel('email') }}</label>
  <input type="email" name="email" value="{{ form.getValue('email') }}">
  {% if form.hasError('email') %}
    <span class="error">{{ form.getError('email') }}</span>
  {% endif %}
</div>

API 模式

对于 JSON 端点,当请求的 Content-Typeapplication/json 时,表单自动返回 JSON:

return form.check(
  onValid: () async => rq.renderData(data: {'success': true}),
  onInvalid: () async => rq.renderData(
    data: {'errors': form.getErrors()},
    statusCode: 422,
  ),
);