Edit
IMPORT MODULE

A higher-order components of the form HTML template. And optimized some details:

  • More friendly form validation status

  • Automated responsive layout

  • Automatic maintenance id

The form HTML template consists of se-container container (directive) and se component, like this:

<form nz-form #f="ngForm" se-container="2">
  <se label="App Key">
    <input type="text" nz-input [(ngModel)]="i.ak" name="ak" required>
  </se>
  <se label="App Secret">
    <input type="text" nz-input [(ngModel)]="i.sk" name="sk" required maxlength="32">
  </se>
  <se>
    <button nz-button nzType="primary" [disabled]="f.invalid">Save</button>
  </se>
</form>

Also, automatically processed all Angular built-in validation, such as required, maxlength, min, pattern, etc., with a red border to indicate invalid value status.

Examples

Basic

1 rows & 2 columns layout form.

expand codeexpand code
import { Component } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd/message';

@Component({
  selector: 'components-se-basic',
  template: ` <form nz-form #f="ngForm" se-container gutter="32">
    <se label="App Key" [error]="{ required: '请填写', pattern: '只能包含a-z, 0-9之间' }">
      <input
        type="text"
        nz-input
        [(ngModel)]="i.ak"
        name="ak"
        required
        pattern="^[a-z0-9]*$"
        placeholder="必填项,且只能包含a-z, 0-9之间"
      />
    </se>
    <ng-template #appSecretRequired> 请填写,密钥<a (click)="msg.success('success')">生成</a>地址。 </ng-template>
    <se label="App Secret" [error]="{ required: appSecretRequired, pattern: '只能包含0-9之间' }">
      <input
        type="text"
        nz-input
        [(ngModel)]="i.sk"
        name="sk"
        required
        maxlength="32"
        pattern="^[0-9]*$"
        placeholder="必填项,且只能包含0-9之间"
      />
    </se>
    <se>
      <button nz-button nzType="primary" [disabled]="f.invalid">Save</button>
    </se>
  </form>`,
})
export class ComponentsSeBasicComponent {
  i: { ak?: string; sk?: string } = {};

  constructor(public msg: NzMessageService) {}
}
Reactive Form

Support for reactive forms.

Note:

  • Reactive form can't auto obtain Validators.required to determine whether a required item identifier is required, so it is necessary to manually identify the required attribute.

  • When you need to use patchValue to assign values, because dirty remains a factor of false, you need to set markAsDirty() on all form elements or use the ingoreDirty attribute to force the dirty check to be ignored.

expand codeexpand code
import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';

import { NzMessageService } from 'ng-zorro-antd/message';

@Component({
  selector: 'components-se-reactive',
  template: ` <form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()" se-container gutter="32" ingoreDirty>
    <se
      label="App Key"
      required
      [error]="{ required: 'Please input your username!', pattern: 'Incorrect format, muse be A' }"
    >
      <input formControlName="userName" nz-input placeholder="Username" />
    </se>
    <se label="App Secret" required error="Please input your Password!">
      <input formControlName="password" nz-input type="password" placeholder="Password" />
    </se>
    <se>
      <button nz-button nzType="primary" [disabled]="!validateForm.valid">Log in</button>
      <button nz-button nzType="link" type="button" (click)="updateValue()">Update value via patchValue</button>
    </se>
  </form>`
})
export class ComponentsSeReactiveComponent {
  validateForm = new FormGroup({
    userName: new FormControl<string | null>(null, [Validators.required, Validators.pattern(/A/)]),
    password: new FormControl(null, [Validators.required]),
    remember: new FormControl(true)
  });
  constructor(private msg: NzMessageService) {}

  submitForm(): void {
    this.msg.success(JSON.stringify(this.validateForm.value));
  }

  updateValue(): void {
    this.validateForm.patchValue({ userName: 'a' });
  }
}
Compact Layout

Force ignored error, extra display.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'components-se-compact',
  template: ` <form nz-form #f="ngForm" se-container labelWidth="150" gutter="32" size="compact">
    <se label="App Key" error="请填写" optional="(选填)" optionalHelp="通过控制台-查看KEY获取" extra="额外提示信息">
      <input type="text" nz-input [(ngModel)]="i.ak" name="ak" required />
    </se>
    <se label="App Secret" error="请填写,最多32位">
      <input type="text" nz-input [(ngModel)]="i.sk" name="sk" required maxlength="32" />
    </se>
    <se>
      <button nz-button nzType="primary" [disabled]="f.invalid">Save</button>
    </se>
  </form>`,
})
export class ComponentsSeCompactComponent {
  i: { ak?: string; sk?: string } = {};
}
额外提示信息
Horizontal Layout

Horizontal layout form.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'components-se-horizontal',
  template: ` <form nz-form #f="ngForm" se-container="1" labelWidth="150">
    <se label="App Key" error="请填写" optional="(选填)" optionalHelp="通过控制台-查看KEY获取" extra="额外提示信息">
      <input type="text" nz-input [(ngModel)]="i.ak" name="ak" required />
    </se>
    <se label="App Secret" error="请填写,最多32位">
      <input type="text" nz-input [(ngModel)]="i.sk" name="sk" required maxlength="32" />
    </se>
    <se>
      <button nz-button nzType="primary" [disabled]="f.invalid">Save</button>
    </se>
  </form>`,
})
export class ComponentsSeHorizontalComponent {
  i: { ak?: string; sk?: string } = {};
}
Inline Layout

If nzLayout: inline is forced to use compact, generally used in the search box.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'components-se-inline',
  template: `
  <form nz-form nzLayout="inline" #f="ngForm" se-container>
    <se label="App Key" error="请填写" optional="(选填)" optionalHelp="通过控制台-查看KEY获取" extra="额外提示信息">
      <input type="text" nz-input [(ngModel)]="i.ak" name="ak" required>
    </se>
    <se label="App Secret" error="请填写,最多32位">
      <input type="text" nz-input [(ngModel)]="i.sk" name="sk" required maxlength="32">
    </se>
    <se>
      <button nz-button nzType="primary" [disabled]="f.invalid">Save</button>
    </se>
  </form>`,
})
export class ComponentsSeInlineComponent {
  i: { ak?: string; sk?: string } = {};
}
额外提示信息
Vertical Layout

Vertical layout form.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'components-se-vertical',
  template: ` <form nz-form nzLayout="vertical" #f="ngForm" se-container>
    <se label="App Key" error="请填写" optional="(选填)" optionalHelp="通过控制台-查看KEY获取" extra="额外提示信息">
      <input type="text" nz-input [(ngModel)]="i.ak" name="ak" required />
    </se>
    <se label="App Secret" error="请填写,最多32位">
      <input type="text" nz-input [(ngModel)]="i.sk" name="sk" required maxlength="32" />
    </se>
    <se>
      <button nz-button nzType="primary" [disabled]="f.invalid">Save</button>
    </se>
  </form>`,
})
export class ComponentsSeVerticalComponent {
  i: { ak?: string; sk?: string } = {};
}
头像
Separation line

Build a standard form row.

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'components-se-line',
  template: ` <form nz-form #f="ngForm" se-container="1" size="compact" gutter="32">
    <se label="所属类目" line>头像</se>
    <se label="图片">
      <nz-input-group nzSearch [nzAddOnAfter]="suffixButton">
        <input type="text" nz-input placeholder="请贴入网络图片地址" />
      </nz-input-group>
      <ng-template #suffixButton>
        <button nz-button nzType="primary" nzSearch>提取</button>
      </ng-template>
    </se>
  </form>`,
})
export class ComponentsSeLineComponent {}

Operating

Reactive

Bulk reset error value

Using errors you can reset error values for all se components in batches.

expand codeexpand code
import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';

import { SEErrorRefresh } from '@delon/abc/se';
import { NzMessageService } from 'ng-zorro-antd/message';

@Component({
  selector: 'components-se-reset-errors',
  template: `
    <h3>Operating</h3>
    <div class="mb-md">
      <button nz-button (click)="resetErrors()">Reset all errors</button>
    </div>
    <form nz-form #f="ngForm" se-container [errors]="ngModelErrors" gutter="32">
      <se label="App Key" [error]="{ required: '请填写', pattern: '只能包含a-z, 0-9之间' }">
        <input
          type="text"
          nz-input
          [(ngModel)]="i.ak"
          name="ak"
          required
          pattern="^[a-z0-9]*$"
          placeholder="必填项,且只能包含a-z, 0-9之间"
        />
      </se>
      <ng-template #appSecretRequired> 请填写,密钥<a (click)="msg.success('success')">生成</a>地址。 </ng-template>
      <se label="App Secret" [error]="{ required: appSecretRequired, pattern: '只能包含0-9之间' }">
        <input
          type="text"
          nz-input
          [(ngModel)]="i.sk"
          name="sk"
          required
          maxlength="32"
          pattern="^[0-9]*$"
          placeholder="必填项,且只能包含0-9之间"
        />
      </se>
      <se>
        <button nz-button nzType="primary" [disabled]="f.invalid">Save</button>
      </se>
    </form>
    <h3>Reactive</h3>
    <form nz-form [formGroup]="validateForm" se-container gutter="32" [errors]="reactiveErrors">
      <se label="App Key" [error]="{ required: 'Please input your username!', pattern: 'Incorrect format, muse be A' }">
        <input formControlName="userName" nz-input placeholder="Username" />
      </se>
      <se label="App Secret" error="Please input your Password!">
        <input formControlName="password" nz-input type="password" placeholder="Password" />
      </se>
      <se>
        <button nz-button nzType="primary" [disabled]="!validateForm.valid">Log in</button>
      </se>
    </form>
  `
})
export class ComponentsSeResetErrorsComponent {
  validateForm = new FormGroup({
    userName: new FormControl<string | null>(null, [Validators.required, Validators.pattern(/A/)]),
    password: new FormControl(null, [Validators.required]),
    remember: new FormControl(true)
  });

  i: { ak?: string; sk?: string } = {};
  ngModelErrors: SEErrorRefresh[] = [];
  reactiveErrors: SEErrorRefresh[] = [];

  constructor(public msg: NzMessageService) {}

  resetErrors(): void {
    this.ngModelErrors = [{ name: 'ak', error: 'Required field, and can only contain a-z, 0-9' }];
    this.reactiveErrors = [
      { name: 'userName', error: 'Required username' },
      { name: 'password', error: 'Required password' }
    ];
  }
}
Title 1
1000
3
+86
Title 2
id

No Data

Irregular Layout

Use col to build complex irregular layouts.

expand codeexpand code
import { Component } from '@angular/core';

import { STColumn } from '@delon/abc/st';

@Component({
  selector: 'components-se-complex',
  template: `
    <form nz-form #f="ngForm" se-container size="compact" gutter="24">
      <se-title>Title 1</se-title>
      <se label="ID" col="1" [optionalHelp]="optionalHelpTpl">
        1000
        <ng-template #optionalHelpTpl> Via by ng-template </ng-template>
      </se>
      <se label="Name" required col="3" optionalHelp="The background color is #f50" optionalHelpColor="#f50">
        <input type="text" nz-input [(ngModel)]="i.user_name" name="user_name" required />
      </se>
      <se label="Age" required col="3">
        <nz-select [(ngModel)]="i.user_age" name="user_age" nzAllowClear nzPlaceHolder="Choose">
          <nz-option [nzValue]="1" nzLabel="1"></nz-option>
          <nz-option [nzValue]="2" nzLabel="2"></nz-option>
          <nz-option [nzValue]="3" nzLabel="3"></nz-option>
          <nz-option [nzValue]="4" nzLabel="4"></nz-option>
          <nz-option [nzValue]="5" nzLabel="5"></nz-option>
        </nz-select>
      </se>
      <se label="Brithday" required col="3">
        <nz-date-picker [(ngModel)]="i.user_birthday" name="user_birthday" nzShowTime></nz-date-picker>
      </se>
      <se label="App Key" required>
        <input type="text" nz-input [(ngModel)]="i.ak" name="ak" required />
      </se>
      <se label="App Secret" required>
        <input type="text" nz-input [(ngModel)]="i.sk" name="sk" required maxlength="32" />
      </se>
      <nz-divider></nz-divider>
      <se label="Phone Number" required>
        <nz-input-group [nzAddOnBefore]="addOnBeforeTemplate">
          <ng-template #addOnBeforeTemplate>
            <nz-select [(ngModel)]="i.phoneNumberPrefix" name="phoneNumberPrefix" style="width: 70px;">
              <nz-option nzLabel="+86" nzValue="+86"></nz-option>
              <nz-option nzLabel="+87" nzValue="+87"></nz-option>
            </nz-select>
          </ng-template>
          <input type="text" nz-input [(ngModel)]="i.phoneNumber" name="phoneNumber" required maxlength="32" />
        </nz-input-group>
      </se>
      <se>
        <label nz-checkbox [(ngModel)]="i.agree" name="agree">
          <span>I have read the <a>agreement</a></span>
        </label>
      </se>
      <se-title>Title 2</se-title>
      <se label="Long Long Long Long Long Long Label" col="1">
        <textarea [(ngModel)]="i.comment" name="comment" nz-input rows="2" placeholder="write any thing"></textarea>
      </se>
      <se hideLabel col="1">
        <st [columns]="columns" size="small"></st>
      </se>
      <se col="1">
        <button nz-button nzType="primary" [disabled]="f.invalid">Save</button>
      </se>
    </form>
  `
})
export class ComponentsSeComplexComponent {
  i = {
    user_name: '',
    user_age: 3,
    user_birthday: '',
    ak: '',
    sk: '',
    phoneNumberPrefix: '+86',
    phoneNumber: '',
    agree: true,
    comment: ''
  };
  columns: STColumn[] = [{ title: 'id' }];
}

API

se-container

PropertyDescriptionTypeDefaultGlobal Config
[gutter]specify the distance between two items, unit is px, only nzLayout:horizontalnumber32
[se-container]specify the maximum number of columns to display, the final columns number is determined by col setting combined with Responsive Rules'1','2','3','4','5','6'-
[col]specify the maximum number of columns to display, the final columns number is determined by col setting combined with Responsive Rules'1','2','3','4','5','6'-
[labelWidth]label text of width, unit is pxnumber150
[nzLayout]type of layout when inline forced size is compact'horizontal','vertical','inline''horizontal'
[size]size of edit, forced ingores error, extra'default','compact''default'
[firstVisual]Immediately show validation error messagebooleanfalse
[ingoreDirty]Whether to ignore the dirty checkbooleanfalse
[line]whether separation line stylebooleanfalse-
[title]Display titlestring,TemplateRef<void>--
[errors]Batch modify se error valueSEErrorRefresh[]-
[noColon]Whether to not display : after label textbooleanfalse-

se

PropertyDescriptionTypeDefault
[col]specify the maximum number of columns to display, the final columns number is determined by col setting combined with Responsive Rules (Inherited from se-container)'1','2','3','4','5','6'-
[label]Labelstring, TemplateRef<void>-
[labelWidth]label text of width, unit is px (Inherited from se-container)number-
[hideLabel]Whether to hide the current labelbooleanfalse
[optional]Label optional informationstring, TemplateRef<void>-
[optionalHelp]Label optional helpstring, TemplateRef<void>-
[optionalHelpColor]The background color of label optional helpstring-
[error]validation error messagestring, TemplateRef<void>, { [key: string]: string, TemplateRef}-
[extra]The extra prompt message. It is similar to help.string, TemplateRef<void>-
[required]Whether required identifier, if not set, the value is automatically set according to whether the form element has RequiredValidator validationstring-
[controlClass]Control area classesstring-
[id]Custom id value of componentstring-
[line]whether separation line style (Inherited from se-container)boolean-
[noColon]Whether to not display : after label textbooleanfalse-

se-title

Display title.

QA

When customize the component id?

Matching for and id values associate the label with the appropriate form control. Because id must be unique, and ng-alain automatic maintenance id. In most cases, you don't need to care about the binding state of id. When you manually specify the id value, the priority is higher, but you also need to maintain the corresponding id value of the component.