zoukankan      html  css  js  c++  java
  • angular11源码探索十七[表单]

    ngModel

    ngModel不能用来把表单控件注册到父formGroup指令中。不然会报错
    如果你想避免注册这个表单控件,请在ngModelOptions中指出它是独立的:

     <input [(ngModel)]="person.firstName" [ngModelOptions]="{standalone: true}">
    

    指令头部

      selector: '[ngModel]:not([formControlName]):not([formControl])',
      exportAs: 'ngModel'
    

    拿出别名,用[(ngModel)] 就别跟formControlName 或者formControl 一起用

    别名的用处很大,可以直接拿到管道内部的内容,这个我们在之前的文章介绍过

    拿到视图展示的内容  
    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();
    

    别名的使用

    <input type="text" [(ngModel)]="a"  #dir='ngModel' [ngModelOptions]="{updateOne:'blur'}">
    <span>{{dir.viewModel}}</span>
    

    ngModel表单部分

    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'
    })
    

    其实越来越感觉这种用法体现了别名的强大之处

    <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()
      }
    

    nGModelGroup

    https://angular.cn/api/forms/NgModelGroup

    @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遗留过来的功能,不建议使用,

    SelectMultipleControlValueAccessor 多选

    选择器

    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 传递数据

    进度条RangeValueAccessor

    选择器

    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" 还是要这样写,以为源码中没有传进去拿不到

    单选RadioControlValueAccessor

    选择器

    • 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;
    

    PatternValidator 正则校验

    选择器

    • [pattern][formControlName]
    • [pattern][formControl]
    • [pattern][ngModel]

    属性

    pattern: string | RegExp
    

    例如

    <input name="firstName" [(ngModel)]="firstName" pattern="[a-zA-Z ]*">
    

    数字NumberValueAccessor

    选择器

    • 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>
    
  • 相关阅读:
    二分数组的一些搜索方法
    获取图像lbp特征
    字符串的模糊搜索
    Python numpy读取图片方法
    红方人员实战手册转载
    libuv的交叉编译
    Gogs的交叉编译与配置
    配置PHP8与Nginx并启动nextcloud
    hi3798mv100SDK上DropBear的交叉编译
    Nginx的交叉编译
  • 原文地址:https://www.cnblogs.com/fangdongdemao/p/14249591.html
Copyright © 2011-2022 走看看