跳到正文

在每个字段旁显示它的错误 ​

机器翻译

本页由英文原文机器翻译而来,尚未经过母语审校,欢迎在 GitHub 上提出修改。内容如有出入,以英文原文为准。

任务: 拒绝一个错误的表单,并在每个字段旁说明它哪里不对。

yaml
# Recipe: the rules live on the action; the form shows each refusal on its field.
paths:
  components: ./components
  migrations: ./migrations

datasources:
  db:
    driver: sqlite
    database: ./data/guests.db
sql
CREATE TABLE guests (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT NOT NULL,
    age INTEGER NOT NULL
);

规则只写一次,写在动作的 q:param 上。ui:form 读取它们并放到自己的字段上 (required、minlength、type="number"、min……),所以浏览器先检查。 服务器会再检查一次,所有字段一起检查:只要有一个失败,动作就不会运行,页面返回, 每个字段显示自己的消息。

xml
<q:component name="Guests">
  <!-- The rules are written once, on the action. The form reads them (UI-9)
       and the server checks them again (ACT-2), every field at once. -->
  <q:action name="register" method="POST">
    <q:param name="name" required="true" minlength="2" maxlength="60" />
    <q:param name="email" type="email" required="true" />
    <q:param name="age" type="integer" required="true" min="18" max="120" />
    <q:query name="added" datasource="db">
      INSERT INTO guests (name, email, age) VALUES (:name, :email, :age)
      <q:param name="name" value="{name}" type="string" />
      <q:param name="email" value="{email}" type="string" />
      <q:param name="age" value="{age}" type="integer" />
    </q:query>
    <q:redirect url="/" flash="{name} is on the list." />
  </q:action>

  <ui:window title="Guest list">
    <q:if condition="flash">
      <ui:alert variant="{flashType == 'error' and 'danger' or 'success'}">{flash}</ui:alert>
    </q:if>
    <ui:form on-submit="register">
      <ui:formitem label="Name"><ui:input bind="name" /></ui:formitem>
      <ui:formitem label="E-mail"><ui:input bind="email" /></ui:formitem>
      <ui:formitem label="Age"><ui:input bind="age" /></ui:formitem>
      <ui:button variant="primary">Add guest</ui:button>
    </ui:form>
  </ui:window>
</q:component>

在测试中,error="field" 检查该字段被拒绝,message= 检查它旁边显示的文本:

xml
<q:test name="a valid guest is added" page="/">
  <test:submit action="register" name="Ana" email="ana@example.com" age="30" />
  <test:expect redirect="/" flash="Ana is on the list." />
  <test:expect table="guests" count="1" where="name = 'Ana' AND age = 30" />
</q:test>

<q:test name="every broken field gets its own message" page="/">
  <test:submit action="register" name="A" email="not an address" age="12" />
  <test:expect redirect="/" />
  <test:expect error="name" message="Must be at least 2 characters" />
  <test:expect error="email" message="Must be a valid email" />
  <test:expect error="age" message="Must be at least 18 (got 12)" />
  <test:expect text="Must be at least 2 characters" />
  <test:expect table="guests" count="0" />
</q:test>

<q:test name="a missing field is refused as Required" page="/">
  <test:submit action="register" name="Ana" email="ana@example.com" />
  <test:expect error="age" message="Required" />
  <test:expect table="guests" count="0" />
</q:test>
text
tests/guests.test.q
  PASS  a valid guest is added
  PASS  every broken field gets its own message
  PASS  a missing field is refused as Required
3 passed, 0 failed

规则及其消息:ACT-2 和 UI-9。

MIT 许可证 · 使用 VitePress 构建