技术标签: angular
在 Angular 中,表单有两种类型,分别为模板驱动
和模型驱动
。
表单的控制逻辑
写在组件模板
中,适合简单
的表单类型。
引入依赖模块 FormsModule
import {
FormsModule } from "@angular/forms"
@NgModule({
imports: [FormsModule],
})
export class AppModule {
}
将 DOM 表单转换为 ngForm
<form #f="ngForm" (submit)="onSubmit(f)"></form>
声明表单字段为 ngModel
<form #f="ngForm" (submit)="onSubmit(f)">
<input type="text" name="username" ngModel />
<button>提交</button>
</form>
获取表单字段值
import {
NgForm } from "@angular/forms"
export class AppComponent {
onSubmit(form: NgForm) {
console.log(form.value) // {username: ''}
}
}
表单分组
<form #f="ngForm" (submit)="onSubmit(f)">
<div ngModelGroup="user">
<input type="text" name="username" ngModel />
</div>
<div ngModelGroup="contact">
<input type="text" name="phone" ngModel />
</div>
<button>提交</button>
</form>
import {
NgForm } from "@angular/forms"
export class AppComponent {
onSubmit(form: NgForm) {
console.log(form.value) // {contact: {phone: ''}, user:{username: ''}}
}
}
<form #f="ngForm" (submit)="onSubmit(f)">
<input type="text" name="username" ngModel required pattern="\d" />
<button>提交</button>
</form>
export class AppComponent {
onSubmit(form: NgForm) {
// 查看表单整体是否验证通过
console.log(form.valid)
}
}
<!-- 表单整体未通过验证时禁用提交表单 -->
<button type="submit" [disabled]="f.invalid">提交</button>
在组件模板中显示表单项未通过时的错误信息。
<form #f="ngForm" (submit)="onSubmit(f)">
<input #username="ngModel" />
<div *ngIf="username.touched && !username.valid && username.errors">
<div *ngIf="username.errors.required">请填写用户名</div>
<div *ngIf="username.errors.pattern">不符合正则规则</div>
</div>
</form>
指定表单项未通过验证时的样式。
input.ng-touched.ng-invalid {
border: 2px solid red;
}
表单的控制逻辑
写在组件类
中,对验证逻辑拥有更多的控制权,适合复杂
的表单的类型。
在模型驱动表单中,表单字段需要是 FormControl
类的实例,实例对象可以验证表单字段
中的值,值是否被修改过等等
一组表单字段构成整个表单,整个表单需要是 FormGroup
类的实例,它可以对表单进行整体
验证。
ReactiveFormsModule
中的 FormControlDirective
提供的引入 ReactiveFormsModule
import {
ReactiveFormsModule } from "@angular/forms"
@NgModule({
imports: [ReactiveFormsModule]
})
export class AppModule {
}
在组件类中创建 FormGroup 表单控制对象
import {
FormControl, FormGroup } from "@angular/forms"
export class AppComponent {
contactForm: FormGroup = new FormGroup({
name: new FormControl(),
phone: new FormControl()
})
}
关联组件模板中的表单
<form [formGroup]="contactForm" (submit)="onSubmit()">
<input type="text" formControlName="name" />
<input type="text" formControlName="phone" />
<button>提交</button>
</form>
获取表单值
export class AppComponent {
onSubmit() {
console.log(this.contactForm.value)
}
}
设置表单默认值
contactForm: FormGroup = new FormGroup({
name: new FormControl("默认值"),
phone: new FormControl(15888888888)
})
表单分组
contactForm: FormGroup = new FormGroup({
fullName: new FormGroup({
firstName: new FormControl(),
lastName: new FormControl()
}),
phone: new FormControl()
})
<form [formGroup]="contactForm" (submit)="onSubmit()">
<div formGroupName="fullName">
<input type="text" formControlName="firstName" />
<input type="text" formControlName="lastName" />
</div>
<input type="text" formControlName="phone" />
<button>提交</button>
</form>
onSubmit() {
console.log(this.contactForm.value.name.username)
console.log(this.contactForm.get(["name", "username"])?.value)
}
需求:在页面中默认显示一组联系方式,通过点击按钮可以添加更多联系方式组。
import {
Component, OnInit } from "@angular/core"
import {
FormArray, FormControl, FormGroup } from "@angular/forms"
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styles: []
})
export class AppComponent implements OnInit {
// 表单
contactForm: FormGroup = new FormGroup({
contacts: new FormArray([])
})
get contacts() {
return this.contactForm.get("contacts") as FormArray
}
// 添加联系方式
addContact() {
// 联系方式
const myContact: FormGroup = new FormGroup({
name: new FormControl(),
address: new FormControl(),
phone: new FormControl()
})
// 向联系方式数组中添加联系方式
this.contacts.push(myContact)
}
// 删除联系方式
removeContact(i: number) {
this.contacts.removeAt(i)
}
ngOnInit() {
// 添加默认的联系方式
this.addContact()
}
onSubmit() {
console.log(this.contactForm.value)
}
}
<form [formGroup]="contactForm" (submit)="onSubmit()">
<div formArrayName="contacts">
<div
*ngFor="let contact of contacts.controls; let i = index"
[formGroupName]="i"
>
<input type="text" formControlName="name" />
<input type="text" formControlName="address" />
<input type="text" formControlName="phone" />
<button (click)="removeContact(i)">删除联系方式</button>
</div>
</div>
<button (click)="addContact()">添加联系方式</button>
<button>提交</button>
</form>
使用内置验证器提供的验证规则验证表单字段
import {
FormControl, FormGroup, Validators } from "@angular/forms"
contactForm: FormGroup = new FormGroup({
name: new FormControl("默认值", [
Validators.required,
Validators.minLength(2)
])
})
获取整体表单是否验证通过
onSubmit() {
console.log(this.contactForm.valid)
}
<!-- 表单整体未验证通过时禁用表单按钮 -->
<button [disabled]="contactForm.invalid">提交</button>
在组件模板中显示为验证通过时的错误信息
get name() {
return this.contactForm.get("name")!
}
<form [formGroup]="contactForm" (submit)="onSubmit()">
<input type="text" formControlName="name" />
<div *ngIf="name.touched && name.invalid && name.errors">
<div *ngIf="name.errors.required">请填写姓名</div>
<div *ngIf="name.errors.maxlength">
姓名长度不能大于
{
{ name.errors.maxlength.requiredLength }} 实际填写长度为
{
{ name.errors.maxlength.actualLength }}
</div>
</div>
</form>
import {
AbstractControl, ValidationErrors } from "@angular/forms"
export class NameValidators {
// 字段值中不能包含空格
static cannotContainSpace(control: AbstractControl): ValidationErrors | null {
// 验证未通过
if (/\s/.test(control.value)) return {
cannotContainSpace: true }
// 验证通过
return null
}
}
import {
NameValidators } from "./Name.validators"
contactForm: FormGroup = new FormGroup({
name: new FormControl("", [
Validators.required,
NameValidators.cannotContainSpace
])
})
<div *ngIf="name.touched && name.invalid && name.errors">
<div *ngIf="name.errors.cannotContainSpace">姓名中不能包含空格</div>
</div>
import {
AbstractControl, ValidationErrors } from "@angular/forms"
import {
Observable } from "rxjs"
export class NameValidators {
static shouldBeUnique(control: AbstractControl): Promise<ValidationErrors | null> {
return new Promise(resolve => {
if (control.value == "admin") {
resolve({
shouldBeUnique: true })
} else {
resolve(null)
}
})
}
}
contactForm: FormGroup = new FormGroup({
name: new FormControl(
"",
[
Validators.required
],
NameValidators.shouldBeUnique
)
})
<div *ngIf="name.touched && name.invalid && name.errors">
<div *ngIf="name.errors.shouldBeUnique">用户名重复</div>
</div>
<div *ngIf="name.pending">正在检测姓名是否重复</div>
创建表单的快捷
方式。
this.fb.control
:表单项this.fb.group
:表单组,表单至少是一个 FormGroupthis.fb.array
:用于复杂表单,可以动态添加表单项或表单组,在表单验证时,FormArray 中有一项没通过,整体没通过。import {
FormBuilder, FormGroup, Validators } from "@angular/forms"
export class AppComponent {
contactForm: FormGroup
constructor(private fb: FormBuilder) {
this.contactForm = this.fb.group({
fullName: this.fb.group({
firstName: ["", [Validators.required]],
lastName: [""]
}),
phone: []
})
}
}
实际工作中,我们常常需要根据某个表单值得变化而进行相应的处理,一般可以使用ngModalChange
或者表单来实现
<div>
<input type="text" [(ngModal)]="name" (ngModalChange)="nameChange()" />
</div>
import {
FormControl, FormGroup } from "@angular/forms"
export class AppComponent {
public name = 'a';
public nameChange() {
}
}
angular官方并不建议使用ngModalChange。
<div [formGroup]="contactForm">
<input type="text" formControlName="name" />
</div>
import {
FormControl, FormGroup } from "@angular/forms"
export class AppComponent {
contactForm: FormGroup = new FormGroup({
name: new FormControl()
})
ngOnInt() {
this.contactForm.get("name").valueChanges.subscribe(data => {
console.log(data);
}
}
}
获取一组复选框中选中的值
<form [formGroup]="form" (submit)="onSubmit()">
<label *ngFor="let item of Data">
<input type="checkbox" [value]="item.value" (change)="onChange($event)" />
{
{ item.name }}
</label>
<button>提交</button>
</form>
import {
Component } from "@angular/core"
import {
FormArray, FormBuilder, FormGroup } from "@angular/forms"
interface Data {
name: string
value: string
}
@Component({
selector: "app-checkbox",
templateUrl: "./checkbox.component.html",
styles: []
})
export class CheckboxComponent {
Data: Array<Data> = [
{
name: "Pear", value: "pear" },
{
name: "Plum", value: "plum" },
{
name: "Kiwi", value: "kiwi" },
{
name: "Apple", value: "apple" },
{
name: "Lime", value: "lime" }
]
form: FormGroup
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
checkArray: this.fb.array([])
})
}
onChange(event: Event) {
const target = event.target as HTMLInputElement
const checked = target.checked
const value = target.value
const checkArray = this.form.get("checkArray") as FormArray
if (checked) {
checkArray.push(this.fb.control(value))
} else {
const index = checkArray.controls.findIndex(
control => control.value === value
)
checkArray.removeAt(index)
}
}
onSubmit() {
console.log(this.form.value)
}
}
获取单选框中选中的值
export class AppComponent {
form: FormGroup
constructor(public fb: FormBuilder) {
this.form = this.fb.group({
gender: "" })
}
onSubmit() {
console.log(this.form.value)
}
}
<form [formGroup]="form" (submit)="onSubmit()">
<input type="radio" value="male" formControlName="gender" /> Male
<input type="radio" value="female" formControlName="gender" /> Female
<button type="submit">Submit</button>
</form>
ReactiveFormsModule
& FormsModule
ReactiveFormsModule
。FormsModule
。文章浏览阅读2.6k次,点赞6次,收藏31次。API 接口文档:API Reference:https://miyakogi.github.io/pyppeteer/reference.html pyppeteergithub 地址:https://github.com/miyakogi/pyppeteer pyppeteer英文文档地址:https://miyakogi.github.i..._pyppeteer
文章浏览阅读170次。@IT程序猿 微博网友评论:@余音袅袅Lena:还有老师站后面看着改bug@月小夕__:我司程序员深有体会@倉優小子:设计师应该感受更深吧@梦中醒不过来:别的架构师 vs..._一编程室友就在旁边看
文章浏览阅读151次。原文地址:https://www.linuxidc.com/Linux/2018-07/153129.htminit是Linux系统操作中不可缺少的程序之一。init进程,它是一个由内核启动的用户级进程。内核会在过去曾使用过init的几个地方查找它,它的正确位置(对Linux系统来说)是/sbin/init。如果内核找不到init,它就会试着运行/bin/sh,如果运行失败,系统的启动也会失败。..._linux的几个运行级别运行界面截图
文章浏览阅读1.5w次,点赞9次,收藏26次。解决 idea maven依赖引入失效,无法正常导入依赖问题idea是真的好用,不过里面的maven依赖问题有时候还真挺让人头疼,不少小伙伴也许会遇到刚配好不久的maven突然就无法正常导入依赖了,或者正满怀激情地看着教学视频想跟着敲一波代码,最后却因依赖无法导入而激情湮灭;又或者开发了挺久的项目哪天敲着敲着代码就一片爆红,一顿猛操作却发现是依赖失效了!又或者诸如…等等。关键是最后试了下网上常用的套路:1.右键 pom.xml -> maven -> reimport;2.File -&g_idea maven失效
文章浏览阅读1k次。import mathimport randomfrom random import sampleimport numpy as npfrom numpy import *import geatpy as eaimport xlrd##已知数据q1='F:\共享车选址调度\共享汽车数据\候选点之间的OD(13).xlsx'T1='F:\共享车选址调度\共享汽车数据\候选点之间的..._遗传算法中最优个体是什么
文章浏览阅读1.1k次。先来看一下微信支付的流程,可见在整个支付流程中后台需要处理的事情有:1、调用统一下单api2、生成JSAPI页面调用的支付参数,并请求支付3、异步通知商户支付结果4、返回微信异步通知的处理结果下面来实际编程实现以上的过程,这里面我们使用了第三方Sdk,best-pay-sdkhttps://github.com/Pay-Group/best-pay-sdkmaven引入依赖 ..._cn.springboot.bestpay
文章浏览阅读5.5k次,点赞4次,收藏89次。效果图用到的图片代码:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>注册页面</title> <style> body{ background: url("../image/register_bg.png") no-repeat center; _register_bg.png图片下载
文章浏览阅读680次。作为一个Java开发人员,有些常用的Linux命令必须掌握.即时平时开发过程中不使用Linux(Unix)或者mac系统,也需要熟练掌握Linux命令.因为很多服务器上都是Linux系统.所以,要和服务器机器交互,就要通过shell命令.1、查找文件find . -name "*.xml" 递归查找所有的xml文件find / -name filename.txt 根据名称查找/目录下的filen..._java为什么要用linux
文章浏览阅读1.1k次。一、前言异步,是指读写时钟频率不同,因此可以用来做跨时钟域处理。跨时钟域处理,单比特的数据一般采用两级寄存器缓存的方式(适用于由慢到快),多比特则采用异步FIFO、异步双口RAM处理。二、原理解析1.空满信号的产生空信号:读地址赶上写地址时产生空信号,因此同步写地址可以小于等于真实写地址,于是将写地址同步到读时钟域进行比较,产生真空或者虚空信号;满信号:写地址赶上读地址时产生满信号,因此同步读地址可以小于等于真实读地址,于是将读地址同步到写时钟域进行比较,产生真满或者虚满信号;2.格雷码的引入_异步fifo count
文章浏览阅读259次。git错误:fatal: unable to access 'https://github.com/baidu/amis.git/': OpenSSL SSL_read: Connection was reset, errno 10054产生原因:一般是这是因为服务器的SSL证书没有经过第三方机构的签署,所以才报错解决办法:解除ssl验证后,再次git即可 git config --global http.sslVerify "false"...
文章浏览阅读3.2k次。1.加入相关依赖: packaging>presto-plugin</packaging> <!--设置presto版本--> <properties> <presto.verison>0.208</presto.verison> </propertie..._presto调用聚合函数的步骤
文章浏览阅读3.3k次,点赞11次,收藏6次。容器退出后,通过 docker container ls 命令查看不到,数据会丢失么?如何停止所有正在运行的容器?如何批量清理已经停止的容器?如何获取某个容器的 PID 信息?如何给容器指定一个固定 IP 地址?如何临时退出一个正在交互的容器的终端,而不终止它?使用 docker port 命令映射容器的端口时,系统报错“Error: No public port ‘80’ published for xxx”?_docker container run停止以后容器消失