
資料驗證是常常碰到的議題,一般說來,前端及後端都要驗證,但常常是前端驗證要寫一套,後端又要寫另一套,不太能共用。JavaScript 的世界也是如此,都會做重工。之前發現套件class-validator,使用 decorator 來設定要驗證的項目,並且是用 Angular 的話,搭配使用ngx-dynamic-form-builder即可進行表單驗證,而在 node.js 也可使用。
npm install class-validator首先使用 npm 安裝 class-validator。
import { IsNotEmpty, IsEmail, IsMobilePhone, Matches, MinLength, MaxLength } from 'class-validator';
export class Member {
  @IsNotEmpty({
    message: '姓名需填寫',
  })
  name = '';
  @IsNotEmpty({
    message: 'Email需填寫',
  })
  @IsEmail()
  email = '';
  @IsNotEmpty({
    message: '手機需填寫',
  })
  @IsMobilePhone('zh-TW', {
    message: '手機需填寫',
  })
  mobile = '';
  @IsNotEmpty(options)
  @MinLength(6, options)
  @MaxLength(12, options)
  @Matches(/[a-zA-Z\d]/g, options)
  account = '';
}使用方式很簡單、直覺,在 class 上設定 decorator 即可。可以使用的 decorator 可以參考文件。並且後面可以傳入參數,來自定錯誤訊息。
import { validateOrReject } from 'class-validator';
try {
  await validateOrReject(member);
  const ret = await memberService.saveMember(member);
  return res.json('ok');
} catch (error) {
  return res.status(500).json({
    message: `errors:${error}`,
  });
}需要驗證資料時呼叫validateOrReject,因為是非同步的所以搭配 await 使用,如果有失敗時,在 catch 中抓取錯誤訊息。
而ngx-dynamic-form-builder這個套件可以將 class-validator 整合進 Angular。
  group: DynamicFormGroup<Member>;
  constructor(
    private fb: DynamicFormBuilder,
  ) {}
  ngOnInit() {
    this.group = this.fb.group(Member);
  }
基於 Reactive forms 的方式開發,會需要用到FormBuilder及FormGroup這兩個物件,而 ngx-dynamic-form-builder 有DynamicFormGroup及DynamicFormBuilder這兩個物件,可以來建立我們的 form。
使用DynamicFormBuilder的Group方法來產生DynamicFormGroup,並且參數傳入 Model 類別。
<form
  [formGroup]="group"
  *ngIf="group?.customValidateErrors | async as errors"
  (ngSubmit)="onSubmit()"
  #form="ngForm"
>
  <div class="form-group">
    <label for="memberName">姓名</label>
    <input
      type="text"
      class="form-control"
      id="memberName"
      placeholder="name"
      formControlName="name"
    />
    <small class="text-danger" *ngIf="errors.name?.length > 0">
      {{ errors.name[0] }}
    </small>
  </div>
</form>顯示錯誤訊息的方式,使用customValidationError屬性,因為型別是 BehavioraSubject,所以這邊先用 async 處理,之後errors.name[0]顯示錯誤訊息。
onSubmit() {
    this.group.validate();
    if (this.group.valid) {
      this.memberService.saveMember(this.group.object).subscribe(() => {
        this.snackBar.open('儲存成功', '', {
          duration: 3000
        });
      });
    }
  }最後儲存資料的階段,使用validate來驗證資料,valid判斷資料是否正確,object取回 model 物件。
只需使用 class-validator 就可以讓前端及後端採用相同的驗證方式,讓程式不用為了驗證重覆再寫一次,並且搭配 ngx-dynamic-form-builder 後,可以輕易地整合至 Angular。
範例程式碼如下form-builder-demo。