ngModel不能用来把表单控件注册到父formGroup指令中。否则会报错
若是你想避免注册这个表单控件,请在ngModelOptions中指出它是独立的:html
<input [(ngModel)]="person.firstName" [ngModelOptions]="{standalone: true}">
指令头部算法
selector: '[ngModel]:not([formControlName]):not([formControl])', exportAs: 'ngModel'
拿出别名,用[(ngModel)]
就别跟formControlName
或者formControl
一块儿用api
别名的用处很大,能够直接拿到管道内部的内容,这个咱们在以前的文章介绍过浏览器
拿到视图展现的内容 viewModel: any; *跟踪绑定到指令的名称。若是父窗体存在,则它 *使用此名称做为键来检索此控件的值。 @Input() name!: string; 是否已禁用。 @Input('disabled') isDisabled!: boolean; @Input('ngModel') model: any; name: 在表单控件元素上设置name属性的另外一种选择 standalone: 当设置为true时,“ngModel”将不会向它的父窗体注册本身,默认值为false uptateOne:定义表单控件值和有效性更新所依据的事件,默认change type FormHooks = 'change'|'blur'|'submit'; @Input('ngModelOptions') options!: {name?: string, standalone?: boolean, updateOn?: FormHooks}; ngModelChange '事件'类型双向绑定,经过事件拿到值 @Output('ngModelChange') update = new EventEmitter();
别名的使用app
<input type="text" [(ngModel)]="a" #dir='ngModel' [ngModelOptions]="{updateOne:'blur'}"> <span>{{dir.viewModel}}</span>
https://angular.cn/api/forms/NgForm函数
@Directive({selector: '[ngModelGroup]', exportAs: 'ngModelGroup'}) @Directive({ selector: 'form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]', //其实我不是很建议把这个写在最外层 from上,毕竟咱们的按钮位置都是不固定 host: {'(submit)': 'onSubmit($event)', '(reset)': 'onReset()'}, outputs: ['ngSubmit'], exportAs: 'ngForm' })
其实愈来愈感受这种用法体现了别名的强大之处ui
<form #f="ngForm"> <!-- name是每一个的属性--> <input name="first" ngModel required #first="ngModel"> <input name="last" ngModel> <button (click)="onSubmit(f)">Submit</button> <button (click)="resetSub(f)">取消</button> </form> onSubmit(f: NgForm) { console.log(f.value) } resetSub(f: NgForm) { f.reset() }
https://angular.cn/api/forms/NgModelGroupthis
@Component({ selector: 'example-app', template: ` <form #f="ngForm" (ngSubmit)="onSubmit(f)"> <p *ngIf="nameCtrl.invalid">Name is invalid.</p> <div ngModelGroup="name" #nameCtrl="ngModelGroup"> <input name="first" [ngModel]="name.first" minlength="2"> <input name="last" [ngModel]="name.last" required> </div> <input name="email" ngModel> <button>Submit</button> </form> <button (click)="setValue()">Set value</button> `, }) export class NgModelGroupComp { name = {first: 'Nancy', last: 'Drew'}; onSubmit(f: NgForm) { console.log(f.value); // {name: {first: 'Nancy', last: 'Drew'}, email: ''} console.log(f.valid); // true } setValue() { this.name = {first: 'Bess', last: 'Marvin'}; } }
上面应该是属于angular.js遗留过来的功能,不建议使用,spa
选择器双向绑定
select[multiple][formControlName] select[multiple][formControl] select[multiple][ngModel]
事件
host: {'(change)': 'onChange($event.target)', '(blur)': 'onTouched()'},
案例一
<label> <select multiple [formControl]="countryControl"> <option *ngFor="let country of countries" [ngValue]="country.sex"> {{ country.name }} </option> </select> </label> 按shift能够模拟选中多个 countryControl = new FormControl(); countries=[ {name:'aaa',sex:1}, {name:'bbb',sex:2}, {name:'ccc',sex:3} ] //检测变化 this.countryControl.valueChanges.subscribe(console.log)
案例二在form表单中
<form [formGroup]="profileFormOne"> <label> <select multiple formControlName="firstName"> <option *ngFor="let country of countries" [ngValue]="country.sex"> {{ country.name }} </option> </select> </label> </form> this.profileFormOne.get('firstName').valueChanges.subscribe(console.log)
案例三
<select multiple [(ngModel)]="countryControl" (ngModelChange)="clickChange($event)"> countryControl = []; clickChange(e) { console.log(e); }
跟踪策略[compareWith]
跟踪用于跟踪身份时的选项比较算法
咱们经过经过FormControl构造函数传递对象引用来设置默认选项。如今的问题是,当咱们从新填充选项列表(例如,经过HTTP调用)时,对象引用消失了,所选值的模型绑定也丢失了。
为了解决这个问题,咱们可使用compareWith指令,该指令将再也不比较对象引用,而是使用布尔表达式或函数
<select [compareWith]="compareFn" [formControl]="selectedCountriesControl"> <option *ngFor="let country of countries" [ngValue]="country"> {{country.name}} </option> </select> compareFn(c1: Country, c2: Country): boolean { return c1 && c2 ? c1.id === c2.id : c1 === c2; } 相似于这样 countries=[ {name:'aaa',id:1}, {name:'bbb',id:2}, {name:'ccc',id:3} ]
咱们看看option
标签
@Directive({selector: 'option'}) ... @Input('ngValue') set ngValue(value: any) { if (this._select == null) return; this._value = value; this._setElementValue(_buildValueString(this.id, value)); this._select.writeValue(this._select.value); } @Input('value') set value(value: any) { if (this._select) { this._value = value; this._setElementValue(_buildValueString(this.id, value)); this._select.writeValue(this._select.value); } else { this._setElementValue(value); } }
也就是你在option
标签能够把经过value
或者ngValue
传递数据
选择器
input[type=range][formControlName] input[type=range][formControl] input[type=range][ngModel]
事件
host: { '(change)': 'onChange($event.target.value)', '(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()' },
跟复选框相似,这个就列举一个demo吧
const firstName=new FormControl(20), <input type="range" [formControl]="firstName" min="10" max="100">
若是须要禁用的话 [attr.disabled]="true"
仍是要这样写,觉得源码中没有传进去拿不到
input[type=radio][formControlName]
input[type=radio][formControl]
input[type=radio][ngModel]
案例
案例一 <form [formGroup]="profileFormOne" > <input type="radio" formControlName="firstName" value="beef" > Beef <input type="radio" formControlName="firstName" value="lamb"> Lamb <input type="radio" formControlName="firstName" value="fish"> Fish </form> 案例二 <input type="radio" [formControl]="firstNames" value="beef" > Beef firstNames=new FormControl() 案例三 其实上面的三个事件也是能够的 <input type="radio" [(ngModel)]="firstNames" value="beef333" (ngModelChange)="clickChange($event)">
事件
host: {'(change)': 'onChange()', '(blur)': 'onTouched()'},
输入的值(这个也挺重要的,帮咱们如何思考怎么写demo) 提供name
属性是可选的。若是有多个单选框的话,仍是建议指定下name的值
@Input() name!: string; @Input() formControlName!: string; @Input() value: any;
[pattern][formControlName]
[pattern][formControl]
[pattern][ngModel]
属性
pattern: string | RegExp
例如
<input name="firstName" [(ngModel)]="firstName" pattern="[a-zA-Z ]*">
input[type=number][formControlName]
input[type=number][formControl]
input[type=number][ngModel]
事件跟前面同样
当之发生改变的回调函数 registerOnChange(fn: (_: number|null) => void): void { this.onChange = (value) => { fn(value == '' ? null : parseFloat(value)); }; } 咱们能够知道主要使用parseFloat
案例
<input type="number" [formControl]="totalCountControl"> const totalCountControl = new FormControl();
默认状况下为全部表单添加novalidate
属性。
novalidate
用于禁用浏览器的原生表单验证。若是你想在Angular表单中使用原生验证,只需添加ngNativeValidate
属性:
<form ngNativeValidate></form>