ng 表单

状态 为真时的 CSS 类 为假时的 CSS 类
控件被访问过。 ng-touched ng-untouched
控件的值变化了。 ng-dirty ng-pristine
控件的值有效。 ng-valid ng-invalid

响应式表单

在模块中导入 ReactiveFormsModule 模块

import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
  imports: [
    // other imports ...
    ReactiveFormsModule
  ],
})
export class AppModule { }

使用 FormControl 注册一个表单控件

<input type="text" [formControl]="name" /> {{ name.value }}

import { FormControl } from "@angular/forms";
name = new FormControl("ajanuw");

设置表单的值

  ngOnInit() {
    setTimeout(() => this.name.setValue("new name"), 2000);
  }

表单控件分组 FormGroup

<form action="" [formGroup]="profileForm" (ngSubmit)="onSubmit()">
  <input type="text" formControlName="name" />
  <input type="text" formControlName="age" />
  <button type="submit" [disabled]="!profileForm.valid">submit</button>
</form>
  import { FormControl, FormGroup } from "@angular/forms";

  profileForm = new FormGroup({
    name: new FormControl("ajanuw"),
    age: new FormControl("14"),
  });

  onSubmit() {
    l(this.profileForm.value);
  }

表单嵌套

<form action="" [formGroup]="profileForm" (ngSubmit)="onSubmit()">
  <input type="text" formControlName="name" />
  <input type="text" formControlName="age" />

  <div formGroupName="address">
    <input type="text" formControlName="street" />
    <input type="text" formControlName="zip" />
  </div>

  <button type="submit" [disabled]="!profileForm.valid">submit</button>
</form>

import { FormControl, FormGroup } from "@angular/forms";

 profileForm = new FormGroup({
    name: new FormControl("ajanuw"),
    age: new FormControl("14"),

    address: new FormGroup({
      street: new FormControl("街道"),
      zip: new FormControl("123"),
    }),

  });

onSubmit() {
    l(this.profileForm.value);
    l(this.profileForm.get('name').value);
  }

部分模型更新

      this.profileForm.patchValue({
        name: "new name",
        address: {
          zip: 233,
        },
      });

使用 FormBuilder 来生成表单控件

数组中的第一项是其初始值,第二项和第三项提供同步和异步验证器

import { FormBuilder } from "@angular/forms";

  profileForm = this.fb.group({
    name: ["ajanuw"],
    age: ["14"],
    address: this.fb.group({
      street: ["街道"],
      zip: ["123"],
    }),
  });

  constructor(private fb: FormBuilder) {}

表单状态

无效的(invalid),有效的(valid)

{{ profileForm.status }}

FormArray

如果你事先不知道子控件的数量,这就是一个很好的选择

import { FormBuilder, Validators, FormArray } from "@angular/forms";

  profileForm = this.fb.group({
    name: ["", Validators.required],
    age: ["14"],
    address: this.fb.group({
      street: ["街道"],
      zip: ["123"],
    }),
    aliases: this.fb.array([this.fb.control("")]),
  });

  ngOnInit() {
    setTimeout(() => {
      this.profileForm.get("aliases") as FormArray;
    }, 2000);
  }

  get aliases() {
    return this.profileForm.get("aliases") as FormArray;
  }

  <div formArrayName="aliases">
    <div *ngFor="let address of aliases.controls; let i = index">
      <input type="text" [formControlName]="i" placeholder="alias" />
    </div>
  </div>

表单验证

<form action="" [formGroup]="info">
  <input type="text" formControlName="name" />
  <div
    *ngIf="name.invalid && (name.dirty || name.touched)"
    class="alert alert-danger"
  >
    <div *ngIf="!!name.errors.required">Name is required.</div>
    <div *ngIf="!!name.errors.minlength">
      Name must be at least 4 characters long.
    </div>
    <div *ngIf="!!name.errors.startKey">必须使用`@`开始</div>
  </div>
  <br />

  <input type="text" formControlName="pwd" placeholder="密码" />
  <div
    *ngIf="pwd.invalid && (pwd.dirty || pwd.touched)"
    class="alert alert-danger"
  >
    <div *ngIf="!!pwd.errors.required">pwd is required.</div>
    <div *ngIf="!!pwd.errors.minlength">
      pwd must be at least 6 characters long.
    </div>
  </div>
  <br />

  <input type="text" formControlName="rpwd" placeholder="确认密码" />
  <div
    *ngIf="rpwd.invalid && (rpwd.dirty || rpwd.touched)"
    class="alert alert-danger"
  >
    <div *ngIf="!!rpwd.errors.required">rpwd is required.</div>
    <div *ngIf="!!rpwd.errors.minlength">
      rpwd must be at least 6 characters long.
    </div>
  </div>
  <br />

  <button type="submit" [disabled]="!info.valid">submit</button>
</form>
import { Component, OnInit } from "@angular/core";
import {
  FormBuilder,
  Validators,
  FormControl,
  AbstractControl,
} from "@angular/forms";
import { startKey } from "src/app/start-key.directive";

@Component({
  selector: "app-welcome",
  templateUrl: "./welcome.component.html",
  styleUrls: ["./welcome.component.css"],
})
export class WelcomeComponent implements OnInit {
  info = this.fb.group({
    name: [
      "",
      {
        updateOn: "blur",
        validators: [
          Validators.required,
          Validators.minLength(5),
          startKey("@"),
        ],
      },
    ],

    pwd: ["", [Validators.required, Validators.minLength(7)]],
    rpwd: ["", [Validators.required, Validators.minLength(7)]],
  });

  get name() {
    const name = this.info.get("name");
    return name;
  }
  get pwd() {
    return this.info.get("pwd");
  }
  get rpwd() {
    return this.info.get("rpwd");
  }
  constructor(private fb: FormBuilder) {}

  ngOnInit() {}
}

与Bootstrap的Form组合


<div
  class="container vw-100 vh-100 d-flex align-items-center justify-content-center"
>
  <form class="w-50" [formGroup]="loginForm" novalidate>
    <div class="mb-3">
      <label class="form-label">{{ "auth.username" | translate }}</label>
      <input
        class="form-control"
        formControlName="username"
        [ngClass]="{
          'is-invalid': username.invalid,
          'is-valid': username.valid
        }"
      />
      <div class="valid-feedback">ok.</div>
      <div class="invalid-feedback">请填写用户名!</div>
    </div>
    <div class="mb-3">
      <label class="form-label">{{ "auth.password" | translate }}</label>
      <input
        type="password"
        formControlName="password"
        class="form-control"
        [ngClass]="{
          'is-invalid': password.invalid,
          'is-valid': password.valid
        }"
      />
      <div *ngIf="password.errors?.required" class="invalid-feedback">
        请填写密码!
      </div>
      <div class="valid-feedback">ok.</div>
      <div *ngIf="password.errors?.minlength" class="invalid-feedback">
        密码最少长度为{{ password.errors?.minlength.requiredLength }}位!
      </div>
    </div>
    <div class="mb-3 form-check">
      <input
        type="checkbox"
        class="form-check-input"
        id="check1"
        formControlName="check"
      />
      <label class="form-check-label user-select-none" for="check1">
        {{ "auth.check" | translate }}</label
      >
    </div>

    <button
      class="btn btn-primary w-100"
      type="button"
      [disabled]="loading || loginForm.invalid"
      (click)="loginForm.valid && login()"
    >
      <span
        *ngIf="loading"
        class="spinner-border spinner-border-sm"
        role="status"
        aria-hidden="true"
      ></span>
      {{ "auth.login" | translate }}
    </button>
  </form>
</div>
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.styl'],
})
export class LoginComponent implements OnInit {
  constructor(
    public readonly fb: FormBuilder,
    public readonly translate: TranslateService,
    private readonly http: HttpClient
  ) {}

  loginForm = this.fb.group({
    username: ['admin', Validators.required],
    password: ['123', [Validators.required, Validators.minLength(3)]],
    check: [true],
  });

  get username() {
    return this.loginForm.get('username');
  }
  get password() {
    return this.loginForm.get('password');
  }

  loading = false;

  ngOnInit(): void {}
  async login() {
    this.loading = true;
    const r = await this.http
      .post('api/login', this.loginForm.value)
      .toPromise();
    this.loading = false;
  }
}
posted @ 2018-12-27 14:47  Ajanuw  阅读(22)  评论(0)    收藏  举报