>웹 프론트엔드 >JS 튜토리얼 >각도의 형태에 대한 깊은 이해(반응형 및 템플릿 기반)

각도의 형태에 대한 깊은 이해(반응형 및 템플릿 기반)

青灯夜游
青灯夜游앞으로
2022-05-13 19:48:113189검색

이 글은 angular의 양식을 안내하고, 반응형 양식과 템플릿 기반 양식에 대해 이야기하고, 반응형 양식이 양식 입력을 확인하는 방법을 소개합니다. 모든 사람에게 도움이 되기를 바랍니다.

각도의 형태에 대한 깊은 이해(반응형 및 템플릿 기반)

1. 각도 양식 소개

Angular는 양식을 통해 사용자 입력을 처리하는 두 가지 방법인 반응형 양식템플릿 기반 양식을 제공합니다. 둘 다 보기에서 사용자 입력 이벤트를 캡처하고, 사용자 입력의 유효성을 검사하고, 양식 모델을 만들고, 데이터 모델을 수정하고, 이러한 변경 사항을 추적하는 방법을 제공합니다. [추천 관련 튜토리얼: "响应式表单模板驱动表单。 两者都从视图中捕获用户输入事件、验证用户输入、创建表单模型、修改数据模型,并提供跟踪这些更改的途径。【相关教程推荐:《angular教程》】

1.1 响应式表单与模板驱动表单的差异

  • 响应式表单提供对底层表单对象模型直接显式的访问。它们与模板驱动表单相比,更加健壮:它们的可扩展性、可复用性和可测试性都更高。如果表单是你的应用程序的关键部分,或者你已经在使用响应式表单来构建应用,那就使用响应式表单。
  • 模板驱动表单依赖模板中的指令angular 튜토리얼
  • "]

1.1 반응형 양식과 템플릿 기반 양식의 차이점
  • 반응형 양식은 기본 양식 개체 모델에는 직접명시적 액세스 권한이 있습니다. 템플릿 기반 양식보다 더 강력합니다. 즉, 확장성, 재사용성, 테스트 가능이 더 뛰어납니다. 양식이 앱의 핵심 부분이거나 이미 반응형 양식을 사용하여 앱을 구축하고 있는 경우 반응형 양식을 사용하세요.
  • 템플릿 기반 양식은 템플릿의 지시문을 사용하여 기본 객체 모델을 생성하고 작동합니다. 이메일 목록 가입 양식과 같은 간단한 양식을 앱에 추가하는 데 유용합니다. 앱에 추가하기는 쉽지만 반응형 양식만큼 확장성이 없습니다. 템플릿 기반 양식은 매우 기본적인 양식 요구 사항과 템플릿에서만 관리할 수 있는 논리가 있는 경우에 적합합니다.
  • 반응형템플릿 기반빌드 폼 모델명시적으로, 구성 요소 클래스에서 생성됨암시적으로, 지침에 따라 생성데이터 모델 ...

    1.2 양식 모델 구축

    반응형 양식과 템플릿 기반 양식 모두 사용자가 상호 작용하는 양식 입력 요소와 구성 요소 모델의 양식 데이터 간의 값 변경을 추적합니다. 두 방법 모두 동일한 기본 빌딩 블록 세트를 공유하지만 일반적으로 사용되는 양식 컨트롤 인스턴스생성관리하는 방법만 다릅니다. > 차이가 있습니다. 构建块,只在如何创建管理常用表单控件实例方面有所不同。

    1.3 常用表单基础类

    响应式表单和模板驱动表单都建立在下列基础类之上。

    • FormControl 实例用于追踪单个表单控件的值和验证状态。
    • FormGroup 用于追踪一个表单控件组的值和状态。
    • FormArray 用于追踪表单控件数组的值和状态。
    • ControlValueAccessor 用于在 Angular 的 FormControl 实例和原生 DOM 元素之间创建一个桥梁。

    二、 响应式表单

    响应式表单使用显式的、不可变的方式,管理表单在特定的时间点上的状态。对表单状态的每一次变更都会返回一个新的状态,这样可以在变化时维护模型的整体性。响应式表单是围绕 Observable 流构建的,表单的输入和值都是通过这些输入值组成的流来提供的,它可以同步访问。

    2.1 添加基础表单控件

    使用表单控件有三个步骤。

    • 在你的应用中注册响应式表单模块。该模块声明了一些你要用在响应式表单中的指令。

    • 生成一个新的 FormControl 实例,并把它保存在组件中。

    • 在模板中注册这个 FormControl。

    要使用响应式表单控件,就要从 @angular/forms 包中导入 ReactiveFormsModule,并把它添加到你的 NgModule 的 imports 数组中。

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

    要注册一个表单控件,就要导入 FormControl 类并创建一个 FormControl 的新实例,将其保存为类的属性。

    import { Component } from '@angular/core';
    import { FormControl } from '@angular/forms';
    
    @Component({
      selector: 'app-name-editor',
      templateUrl: './name-editor.component.html',
      styleUrls: ['./name-editor.component.css']
    })
    export class NameEditorComponent {
      name = new FormControl('');
    }

    可以用 FormControl 的构造函数设置初始值,这个例子中它是空字符串。通过在你的组件类中创建这些控件,你可以直接对表单控件的状态进行监听修改校验

    在组件类中创建了控件之后,你还要把它和模板中的一个表单控件关联起来。修改模板,为表单控件添加 formControl 绑定,formControl 是由 ReactiveFormsModule 中的 FormControlDirective 提供的。

    <label>
      Name:
      <input type="text" [formControl]="name">
    </label>

    2.2 显示表单控件的值

    你可以用下列方式显示它的值:

    • 通过可观察对象 valueChanges,你可以在模板中使用 AsyncPipe 或在组件类中使用 subscribe() 方法来监听表单值的变化。
    • 使用 value 属性。它能让你获得当前值的一份快照。
    <label>
      Name:
      <input type="text" [formControl]="name">
    </label>
    

    Value: {{ name.value }}

      public name = new FormControl(&#39;test&#39;);
    
      public testValueChange() {
        this.name.valueChanges.subscribe({
          next: value => {
            console.log("name value is: " + value);
          }
        })
      }

    2.3 替换表单控件的值

    响应式表单还有一些方法可以用编程的方式``修改控件的值,它让你可以灵活的修改控件的值而不需要借助用户交互。FormControl 提供了一个 setValue() 方法,它会修改这个表单控件的值,并且验证与控件结构相对应的值的结构。比如,当从后端 API 或服务接收到了表单数据时,可以通过 setValue() 方法来把原来的值替换为新的值。

    updateName() {
      this.name.setValue(&#39;Nancy&#39; + new Date().getTime());
    }
    <p>
      <button (click)="updateName()">Update Name</button>
    </p>

    2.4 把表单控件分组

    表单中通常会包含几个相互关联的控件。响应式表单提供了两种把多个相关控件分组到同一个输入表单中的方法。

    • 表单组定义了一个带有一组控件的表单,你可以把它们放在一起管理。表单组的基础知识将在本节中讨论。你也可以通过嵌套表单组来创建更复杂的表单。
    • 表单数组定义了一个动态表单,你可以在运行时添加和删除控件。你也可以通过嵌套表单数组来创建更复杂的表单

    要将表单组添加到此组件中,请执行以下步骤。

    • 创建一个 FormGroup

    • 1.3 일반적으로 사용되는 양식 기본 클래스
    • 반응형 양식과 템플릿 기반 양식은 모두 다음 기본 클래스를 기반으로 구축됩니다.
      • FormControl 인스턴스는 개별 양식 컨트롤의 값과 유효성 검사 상태를 추적하는 데 사용됩니다.

        FormGroup은 양식 제어 그룹의 값과 상태를 추적하는 데 사용됩니다.
      FormArray는 양식 컨트롤 배열의 값과 상태를 추적하는 데 사용됩니다.

      ControlValueAccessor는 Angular의 FormControl 인스턴스와 기본 DOM 요소 사이에 브리지를 만드는 데 사용됩니다.

      🎜

      🎜 2. 반응형 양식 🎜

      🎜반응형 양식은 특정 시점의 양식 상태를 관리하기 위해 명시적이고 불변적인 방식을 사용합니다. 양식 상태가 변경될 때마다 새 상태가 반환되므로 변경 시 모델의 무결성이 유지됩니다. 반응형 양식은 관찰 가능 스트림을 중심으로 구축되며 양식의 입력 및 값은 동기적으로 액세스할 수 있는 이러한 입력 값의 스트림을 통해 제공됩니다. 🎜🎜🎜2.1 기본 양식 컨트롤 추가 🎜🎜🎜양식 컨트롤을 사용하려면 세 단계를 거쳐야 합니다. 🎜
        🎜🎜앱에 반응형 양식 모듈을 등록하세요. 이 모듈은 반응형 형식에서 사용하려는 일부 지시문을 선언합니다. 🎜🎜🎜🎜새 FormControl 인스턴스를 생성하고 구성 요소에 저장합니다. 🎜🎜🎜🎜이 FormControl을 템플릿에 등록하세요. 🎜🎜🎜🎜🎜반응형 양식 컨트롤을 사용하려면 @angular/forms 패키지에서 ReactiveFormsModule을 가져와서 NgModule의 가져오기 배열에 추가하세요. 🎜
      import { FormControl, FormGroup } from &#39;@angular/forms&#39;;
        profileForm = new FormGroup({
          firstName: new FormControl(&#39;&#39;),
          lastName: new FormControl(&#39;&#39;),
        });
        // 可以整个获取值
        public onSubmit() {
          // TODO: Use EventEmitter with form value
          console.warn(this.profileForm.value);// {firstName: "", lastName: ""}
        }
            // 可以借助 valueChanges 整个可观察对象整个获取值
           this.profileForm.valueChanges.subscribe( {
            next: value => {
              console.log("name value is: " + JSON.stringify(value)); // dashboard.component.ts:53 name value is: {"firstName":"dddd","lastName":"bb"}
            }
          })
      
          // 可以通过后期单个控件单独获取值
          this.profileForm.get(&#39;firstName&#39;).valueChanges.subscribe({
            next: value => {
              console.log("First Name is: " + value); // First Name is: aa
            }
      🎜🎜양식 컨트롤을 등록하려면 FormControl 클래스를 가져오고 FormControl의 새 인스턴스를 만들어 클래스 속성으로 저장하세요. 🎜
      <form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
       
        <label>
          First Name:
          <input type="text" formControlName="firstName">
        </label>
      
        <label>
          Last Name:
          <input type="text" formControlName="lastName">
        </label>
      
        <button type="submit" [disabled]="!profileForm.valid">Submit</button>
      </form>
      🎜FormControl의 생성자를 사용하여 초기 값을 설정할 수 있습니다. 이 예에서는 빈 문자열입니다. 구성 요소 클래스에 이러한 컨트롤을 생성하면 양식 컨트롤의 상태를 직접 모니터링, 수정확인할 수 있습니다. 🎜🎜🎜구성 요소 클래스에서 컨트롤을 만든 후에는 이를 템플릿의 양식 컨트롤과 연결해야 합니다. 템플릿을 수정하고 양식 컨트롤에 formControl 바인딩을 추가합니다. formControl은 ReactiveFormsModule의 FormControlDirective에서 제공됩니다. 🎜
        public profileForm = new FormGroup({
          firstName: new FormControl(&#39;&#39;),
          lastName: new FormControl(&#39;&#39;),
          address: new FormGroup({
            street: new FormControl(&#39;&#39;),
            city: new FormControl(&#39;&#39;),
            state: new FormControl(&#39;&#39;),
            zip: new FormControl(&#39;&#39;)
          })
        });
          // 可以借助 valueChanges 整个可观察对象整个获取值
          this.profileForm.valueChanges.subscribe( {
            next: value => {
              console.log("name value is: " + JSON.stringify(value));// name value is: {"firstName":"","lastName":"","address":{"street":"b","city":"","state":"","zip":""}}
            }
          });
      
          // 可以通过后期单个控件单独获取值
          this.profileForm.get(&#39;firstName&#39;).valueChanges.subscribe({
            next: value => {
              console.log("First Name is: " + value);
            }
          });
      
          // 可以获取form组件某个form组的整个值
          this.profileForm.get(&#39;address&#39;).valueChanges.subscribe(({
            next: value => {
              console.log(&#39;address value is: &#39; + JSON.stringify(value));// address value is: {"street":"b","city":"","state":"","zip":""}
            }
          }));
      
          // 可以获取form组件某个form组的某个formcontrol实例的值
          this.profileForm.get(&#39;address&#39;).get(&#39;street&#39;).valueChanges.subscribe(({
            next: value => {
              console.log(&#39;street value is: &#39; + value);// street value is: b
            }
          }));
      🎜🎜2.2 양식 컨트롤의 값 표시 🎜🎜🎜다음과 같은 방법으로 해당 값을 표시할 수 있습니다. 🎜
        🎜관찰 가능한 valueChanges를 사용하여 표시할 수 있습니다. 템플릿에서 AsyncPipe를 사용하거나 구성 요소 클래스의 subscribe() 메서드를 사용하여 양식 값의 변경 사항을 수신합니다. 🎜🎜값 속성을 사용하세요. 이를 통해 현재 값의 스냅샷을 얻을 수 있습니다. 🎜🎜
              <form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
        
                <label>
                  First Name:
                  <input type="text" formControlName="firstName">
                </label>
        
                <label>
                  Last Name:
                  <input type="text" formControlName="lastName">
                </label>
                <div formGroupName="address">
                  <h3>Address</h3>
        
                  <label>
                    Street:
                    <input type="text" formControlName="street">
                  </label>
        
                  <label>
                    City:
                    <input type="text" formControlName="city">
                  </label>
        
                  <label>
                    State:
                    <input type="text" formControlName="state">
                  </label>
        
                  <label>
                    Zip Code:
                    <input type="text" formControlName="zip">
                  </label>
                </div>
                <button type="submit" [disabled]="!profileForm.valid">Submit</button>
              </form>
          public updateProfile() {
              // profileForm 模型中只有 firstName 和 street 被修改了。注意,street 是在 address 属性的对象中被修改的。这种结构是必须的,因为 patchValue() 方法要针对模型的结构进行更新。patchValue() 只会更新表单模型中所定义的那些属性。
            this.profileForm.patchValue({
              firstName: &#39;Nancy&#39; + new Date().getTime(),
              address: {
                street: &#39;123 Drew Street&#39; + new Date().getTime()
              }
            });
        
            // ERROR Error: Must supply a value for form control with name: &#39;lastName&#39;.
            // setValue() 方法会严格遵循表单组的结构
            this.profileForm.setValue({
              firstName: &#39;Nancy&#39; + new Date().getTime(),
              address: {
                street: &#39;123 Drew Street&#39; + new Date().getTime()
              }
            });
          }
        🎜🎜2.3 양식 컨트롤 값 바꾸기 🎜🎜🎜반응형 양식에는 프로그래밍 방식으로 컨트롤 값을 ``수정하는 몇 가지 메서드가 있으므로 사용자 상호 작용이 필요합니다. FormControl은 이 양식 컨트롤의 값을 수정하고 컨트롤 구조에 해당하는 값의 구조를 확인하는 setValue() 메서드를 제공합니다. 예를 들어 백엔드 API나 서비스로부터 양식 데이터를 수신하면 setValue() 메서드를 통해 원래 값을 새 값으로 바꿀 수 있습니다. 🎜
        import { FormControl, FormGroup, FormArray } from &#39;@angular/forms&#39;;
        
          public profileForm = new FormGroup({
            firstName: new FormControl(&#39;&#39;),
            lastName: new FormControl(&#39;&#39;),
            address: new FormGroup({
              street: new FormControl(&#39;&#39;),
              city: new FormControl(&#39;&#39;),
              state: new FormControl(&#39;&#39;),
              zip: new FormControl(&#39;&#39;)
            }),
            aliases: new FormArray([
              new FormControl(&#39;1&#39;)
            ])
          });
          public aliases = (<FormArray>this.profileForm.get(&#39;aliases&#39;));
        
          public addAlias() {
            (<FormArray>this.profileForm.get(&#39;aliases&#39;)).push(new FormControl(&#39;1&#39;));
          }
        
              // 获取整个 formArray 的数据
            this.profileForm.get(&#39;aliases&#39;).valueChanges.subscribe({
              next: value => {
                console.log(&#39;aliases values is: &#39; + JSON.stringify(value)); // aliases values is: ["1","3"]
              }
            });
        
            // 获取 formArray 中单个 formControl 的数据
            (<FormArray>this.profileForm.get(&#39;aliases&#39;)).controls[0].valueChanges.subscribe({
              next: value => {
                console.log(&#39;aliases[0] values is: &#39; + value); // aliases[0] values is: 0
              }
            })
              <form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
        
                <label>
                  First Name:
                  <input type="text" formControlName="firstName">
                </label>
        
                <label>
                  Last Name:
                  <input type="text" formControlName="lastName">
                </label>
                <div formGroupName="address">
                  <h3>Address</h3>
        
                  <label>
                    Street:
                    <input type="text" formControlName="street">
                  </label>
        
                  <label>
                    City:
                    <input type="text" formControlName="city">
                  </label>
        
                  <label>
                    State:
                    <input type="text" formControlName="state">
                  </label>
        
                  <label>
                    Zip Code:
                    <input type="text" formControlName="zip">
                  </label>
                </div>
                <div formArrayName="aliases">
                  <h3>Aliases</h3> <button (click)="addAlias()">Add Alias</button>
        
                  <div *ngFor="let alias of aliases.controls; let i=index">
                    <!-- The repeated alias template -->
                    <label>
                      Alias:
                      <input type="text" [formControlName]="i">
                    </label>
                  </div>
                </div>
              </form>
        🎜🎜2.4 그룹 양식 컨트롤🎜🎜🎜양식에는 일반적으로 여러 상호 연관된 컨트롤이 포함되어 있습니다. 반응형 양식은 여러 관련 컨트롤을 동일한 입력 양식으로 그룹화하는 두 가지 방법을 제공합니다. 🎜
          🎜양식 그룹은 함께 관리할 수 있는 일련의 컨트롤이 포함된 양식을 정의합니다. 이 섹션에서는 양식 그룹의 기본 사항에 대해 설명합니다. 중첩된 양식 그룹을 통해 더 복잡한 양식을 만들 수도 있습니다. 🎜🎜양식 배열은 런타임에 컨트롤을 추가하고 제거할 수 있는 동적 양식을 정의합니다. 중첩된 양식 배열을 사용하여 더 복잡한 양식을 만들 수도 있습니다.🎜🎜🎜이 구성 요소에 양식 그룹을 추가하려면 아래 단계를 따르세요. 🎜
            🎜🎜FormGroup 인스턴스를 생성합니다. 🎜🎜🎜🎜이 FormGroup 모델을 뷰에 연결합니다. 🎜🎜🎜🎜양식 데이터를 저장합니다. 🎜🎜🎜🎜🎜구성 요소 클래스에 profileForm이라는 속성을 생성하고 이를 FormGroup의 새 인스턴스로 설정합니다. 이 FormGroup을 초기화하려면 컨트롤로 구성된 개체를 생성자에 제공합니다. 개체의 각 이름은 양식 컨트롤의 이름과 일치해야 합니다. 🎜
            import { FormControl, FormGroup } from &#39;@angular/forms&#39;;
              profileForm = new FormGroup({
                firstName: new FormControl(&#39;&#39;),
                lastName: new FormControl(&#39;&#39;),
              });
              // 可以整个获取值
              public onSubmit() {
                // TODO: Use EventEmitter with form value
                console.warn(this.profileForm.value);// {firstName: "", lastName: ""}
              }
                  // 可以借助 valueChanges 整个可观察对象整个获取值
                 this.profileForm.valueChanges.subscribe( {
                  next: value => {
                    console.log("name value is: " + JSON.stringify(value)); // dashboard.component.ts:53 name value is: {"firstName":"dddd","lastName":"bb"}
                  }
                })
            
                // 可以通过后期单个控件单独获取值
                this.profileForm.get(&#39;firstName&#39;).valueChanges.subscribe({
                  next: value => {
                    console.log("First Name is: " + value); // First Name is: aa
                  }

            ps: 这个 FormGroup 用对象的形式提供了它的模型值,这个值来自组中每个控件的值。 FormGroup 实例拥有和 FormControl 实例相同的属性(比如 value、untouched)和方法(比如 setValue())。

            这个表单组还能跟踪其中每个控件的状态及其变化,所以如果其中的某个控件的状态或值变化了,父控件也会发出一次新的状态变更或值变更事件。该控件组的模型来自它的所有成员。在定义了这个模型之后,你必须更新模板,来把该模型反映到视图中。

            <form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
             
              <label>
                First Name:
                <input type="text" formControlName="firstName">
              </label>
            
              <label>
                Last Name:
                <input type="text" formControlName="lastName">
              </label>
            
              <button type="submit" [disabled]="!profileForm.valid">Submit</button>
            </form>

            2.5 创建嵌套的表单组

            表单组可以同时接受单个表单控件实例和其它表单组实例作为其子控件。这可以让复杂的表单模型更容易维护,并在逻辑上把它们分组到一起。
            要制作更复杂的表单,请遵循如下步骤。

            • 创建一个嵌套的表单组

            • 板中对这个嵌套表单分组。

            要在 profileForm 中创建一个嵌套组,就要把一个嵌套的 address 元素添加到此表单组的实例中。

              public profileForm = new FormGroup({
                firstName: new FormControl(&#39;&#39;),
                lastName: new FormControl(&#39;&#39;),
                address: new FormGroup({
                  street: new FormControl(&#39;&#39;),
                  city: new FormControl(&#39;&#39;),
                  state: new FormControl(&#39;&#39;),
                  zip: new FormControl(&#39;&#39;)
                })
              });
                // 可以借助 valueChanges 整个可观察对象整个获取值
                this.profileForm.valueChanges.subscribe( {
                  next: value => {
                    console.log("name value is: " + JSON.stringify(value));// name value is: {"firstName":"","lastName":"","address":{"street":"b","city":"","state":"","zip":""}}
                  }
                });
            
                // 可以通过后期单个控件单独获取值
                this.profileForm.get(&#39;firstName&#39;).valueChanges.subscribe({
                  next: value => {
                    console.log("First Name is: " + value);
                  }
                });
            
                // 可以获取form组件某个form组的整个值
                this.profileForm.get(&#39;address&#39;).valueChanges.subscribe(({
                  next: value => {
                    console.log(&#39;address value is: &#39; + JSON.stringify(value));// address value is: {"street":"b","city":"","state":"","zip":""}
                  }
                }));
            
                // 可以获取form组件某个form组的某个formcontrol实例的值
                this.profileForm.get(&#39;address&#39;).get(&#39;street&#39;).valueChanges.subscribe(({
                  next: value => {
                    console.log(&#39;street value is: &#39; + value);// street value is: b
                  }
                }));

            在修改了组件类中的模型之后,还要修改模板,来把这个 FormGroup 实例对接到它的输入元素。

                  <form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
            
                    <label>
                      First Name:
                      <input type="text" formControlName="firstName">
                    </label>
            
                    <label>
                      Last Name:
                      <input type="text" formControlName="lastName">
                    </label>
                    <div formGroupName="address">
                      <h3>Address</h3>
            
                      <label>
                        Street:
                        <input type="text" formControlName="street">
                      </label>
            
                      <label>
                        City:
                        <input type="text" formControlName="city">
                      </label>
            
                      <label>
                        State:
                        <input type="text" formControlName="state">
                      </label>
            
                      <label>
                        Zip Code:
                        <input type="text" formControlName="zip">
                      </label>
                    </div>
                    <button type="submit" [disabled]="!profileForm.valid">Submit</button>
                  </form>

            2.6 更新部分数据模型

            当修改包含多个 FormGroup 实例的值时,你可能只希望更新模型中的一部分,而不是完全替换掉。

            有两种更新模型值的方式:

            • 使用 setValue() 方法来为单个控件设置新值。 setValue() 方法会严格遵循表单组的结构,并整体性替换控件的值
            • 使用 patchValue() 方法可以用对象中所定义的任何属性为表单模型进行替换。

            setValue() 方法的严格检查可以帮助你捕获复杂表单嵌套中的错误,而 patchValue() 在遇到那些错误时可能会默默的失败。

              public updateProfile() {
                  // profileForm 模型中只有 firstName 和 street 被修改了。注意,street 是在 address 属性的对象中被修改的。这种结构是必须的,因为 patchValue() 方法要针对模型的结构进行更新。patchValue() 只会更新表单模型中所定义的那些属性。
                this.profileForm.patchValue({
                  firstName: &#39;Nancy&#39; + new Date().getTime(),
                  address: {
                    street: &#39;123 Drew Street&#39; + new Date().getTime()
                  }
                });
            
                // ERROR Error: Must supply a value for form control with name: &#39;lastName&#39;.
                // setValue() 方法会严格遵循表单组的结构
                this.profileForm.setValue({
                  firstName: &#39;Nancy&#39; + new Date().getTime(),
                  address: {
                    street: &#39;123 Drew Street&#39; + new Date().getTime()
                  }
                });
              }

            2.7 创建动态表单

            FormArray 是 FormGroup 之外的另一个选择,用于管理任意数量的匿名控件。像 FormGroup 实例一样,你也可以往 FormArray 中动态插入和移除控件,并且 FormArray 实例的值和验证状态也是根据它的子控件计算得来的。 不过,你不需要为每个控件定义一个名字作为 key,因此,如果你事先不知道子控件的数量,这就是一个很好的选择。

            要定义一个动态表单,请执行以下步骤。

            • 导入 FormArray 类。

            • 定义一个 FormArray 控件。

            • 使用 getter 方法访问 FormArray 控件。

            • 在模板中显示这个表单数组

            通过把一组(从零项到多项)控件定义在一个数组中来初始化一个 FormArray。为 profileForm 添加一个 aliases 属性,把它定义为 FormArray 类型。

            import { FormControl, FormGroup, FormArray } from &#39;@angular/forms&#39;;
            
              public profileForm = new FormGroup({
                firstName: new FormControl(&#39;&#39;),
                lastName: new FormControl(&#39;&#39;),
                address: new FormGroup({
                  street: new FormControl(&#39;&#39;),
                  city: new FormControl(&#39;&#39;),
                  state: new FormControl(&#39;&#39;),
                  zip: new FormControl(&#39;&#39;)
                }),
                aliases: new FormArray([
                  new FormControl(&#39;1&#39;)
                ])
              });
              public aliases = (<FormArray>this.profileForm.get(&#39;aliases&#39;));
            
              public addAlias() {
                (<FormArray>this.profileForm.get(&#39;aliases&#39;)).push(new FormControl(&#39;1&#39;));
              }
            
                  // 获取整个 formArray 的数据
                this.profileForm.get(&#39;aliases&#39;).valueChanges.subscribe({
                  next: value => {
                    console.log(&#39;aliases values is: &#39; + JSON.stringify(value)); // aliases values is: ["1","3"]
                  }
                });
            
                // 获取 formArray 中单个 formControl 的数据
                (<FormArray>this.profileForm.get(&#39;aliases&#39;)).controls[0].valueChanges.subscribe({
                  next: value => {
                    console.log(&#39;aliases[0] values is: &#39; + value); // aliases[0] values is: 0
                  }
                })

            要想为表单模型添加 aliases,你必须把它加入到模板中供用户输入。和 FormGroupNameDirective 提供的 formGroupName 一样,FormArrayNameDirective 也使用 formArrayName 在这个 FormArray 实例和模板之间建立绑定

                  <form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
            
                    <label>
                      First Name:
                      <input type="text" formControlName="firstName">
                    </label>
            
                    <label>
                      Last Name:
                      <input type="text" formControlName="lastName">
                    </label>
                    <div formGroupName="address">
                      <h3>Address</h3>
            
                      <label>
                        Street:
                        <input type="text" formControlName="street">
                      </label>
            
                      <label>
                        City:
                        <input type="text" formControlName="city">
                      </label>
            
                      <label>
                        State:
                        <input type="text" formControlName="state">
                      </label>
            
                      <label>
                        Zip Code:
                        <input type="text" formControlName="zip">
                      </label>
                    </div>
                    <div formArrayName="aliases">
                      <h3>Aliases</h3> <button (click)="addAlias()">Add Alias</button>
            
                      <div *ngFor="let alias of aliases.controls; let i=index">
                        <!-- The repeated alias template -->
                        <label>
                          Alias:
                          <input type="text" [formControlName]="i">
                        </label>
                      </div>
                    </div>
                  </form>

            2.8 响应式表单 API 汇总


    说明
    AbstractControl 所有三种表单控件类(FormControl、FormGroup 和 FormArray)的抽象基类。它提供了一些公共的行为和属性。
    FormControl 管理单体表单控件的值和有效性状态。它对应于 HTML 的表单控件,比如 或 。
    FormGroup 管理一组 AbstractControl 实例的值和有效性状态。该组的属性中包括了它的子控件。组件中的顶层表单就是 FormGroup。
    FormArray 管理一些 AbstractControl 实例数组的值和有效性状态。
    FormBuilder 一个可注入的服务,提供一些用于提供创建控件实例的工厂方法。

    三、模板驱动表单

    在模板驱动表单中,表单模型是隐式的,而不是显式的。指令 NgModel 为指定的表单元素创建并管理一个 FormControl 实例。
    下面的组件使用模板驱动表单为单个控件实现了同样的输入字段。

    import { Component } from &#39;@angular/core&#39;;
    
    @Component({
      selector: &#39;app-template-favorite-color&#39;,
      template: `
        Favorite Color: <input type="text" [(ngModel)]="favoriteColor">
      `
    })
    export class FavoriteColorComponent {
      favoriteColor = &#39;&#39;;
    }

    四、响应式表单验证表单输入

    在组件类中直接把验证器函数添加到表单控件模型上(FormControl)。然后,一旦控件发生了变化,Angular 就会调用这些函数。

    4.1 验证器(Validator)函数

    验证器函数可以是同步函数,也可以是异步函数。

    • 同步验证器:这些同步函数接受一个控件实例,然后返回一组验证错误或 null。你可以在实例化一个 FormControl 时把它作为构造函数的第二个参数传进去。
    • 异步验证器 :这些异步函数接受一个控件实例并返回一个 Promise 或 Observable,它稍后会发出一组验证错误或 null。在实例化 FormControl 时,可以把它们作为第三个参数传入。

    出于性能方面的考虑,只有在所有同步验证器都通过之后,Angular 才会运行异步验证器。当每一个异步验证器都执行完之后,才会设置这些验证错误。

    4.2 内置验证器函数

    在模板驱动表单中用作属性的那些内置验证器,比如 required 和 minlength,也都可以作为 Validators 类中的函数使用

     public profileForm = new FormGroup({
        firstName: new FormControl(&#39;&#39;, [
          Validators.required
        ]),
      });
    
        this.profileForm.get(&#39;firstName&#39;).valueChanges.subscribe({
          next: value => {
            console.log("First Name is: " + value);
            console.log(this.profileForm.get(&#39;firstName&#39;).errors);// { required: true } | null
          }
        });
          <form [formGroup]="profileForm">
    
            <label>
              First Name:
              <input type="text" formControlName="firstName">
              <div *ngIf="firstName.errors?.required">
                Name is required.
              </div>
            </label>
        </form>

    4.3 定义自定义验证器

    内置的验证器并不是总能精确匹配应用中的用例,因此有时你需要创建一个自定义验证器。

      public profileForm = new FormGroup({
        firstName: new FormControl(&#39;&#39;, [
          Validators.required,
          this.forbiddenNameValidator(/bob/i)
        ])
      });
    
      public forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
        return (control: AbstractControl): {[key: string]: any} | null => {
          const forbidden = nameRe.test(control.value);
          return forbidden ? {forbiddenName: {value: control.value}} : null;
        };
      }
    
      get firstName() { return this.profileForm.get(&#39;firstName&#39;); }
    
    
    
          this.profileForm.get(&#39;firstName&#39;).valueChanges.subscribe({
          next: value => {
            console.log("First Name is: " + value); // First Name is: bob
            console.log(JSON.stringify(this.profileForm.get(&#39;firstName&#39;).errors));// {"forbiddenName":{"value":"bob"}} | null
          }
        });

    4.4 跨字段交叉验证

    跨字段交叉验证器是一种自定义验证器,可以对表单中不同字段的值进行比较,并针对它们的组合进行接受或拒绝。

    下列交叉验证的例子说明了如何进行如下操作:

    • 根据两个兄弟控件的值验证响应式表单或模板驱动表单的输入,
    • 当用户与表单交互过,且验证失败后,就会显示描述性的错误信息

    要想在单个自定义验证器中计算这两个控件,你就必须在它们共同的祖先控件中执行验证: FormGroup。你可以在 FormGroup 中查询它的子控件,从而让你能比较它们的值。要想给 FormGroup 添加验证器,就要在创建时把一个新的验证器传给它的第二个参数。

        this.profileForm.valueChanges.subscribe( {
          next: value => {
            console.log(JSON.stringify(this.profileForm.errors));// {"identityRevealed":true} | null
          }
        });
    
      public profileForm = new FormGroup({
        firstName: new FormControl(&#39;&#39;, [
          Validators.required,
        ]),
        lastName: new FormControl(&#39;&#39;),
      }, { validators: this.identityRevealedValidator});
    
      public identityRevealedValidator(control: FormGroup): ValidationErrors | null{
        const firstName = control.get(&#39;firstName&#39;);
        const lastName = control.get(&#39;lastName&#39;);
        return firstName && lastName && firstName.value === lastName.value ? { identityRevealed: true } : null;
      };

    4.5 创建异步验证器

    异步验证器实现了 AsyncValidatorFnAsyncValidator 接口。它们与其同步版本非常相似,但有以下不同之处。

    • validate() 函数必须返回一个 Promise 或可观察对象
    • 返回的可观察对象必须是有尽的,这意味着它必须在某个时刻完成(complete)。要把无尽的可观察对象转换成有尽的,可以在管道中加入过滤操作符,比如 first、last、take 或 takeUntil。

    异步验证在同步验证完成后才会发生,并且只有在同步验证成功时才会执行。如果更基本的验证方法已经发现了无效输入,那么这种检查顺序就可以让表单避免使用昂贵的异步验证流程(例如 HTTP 请求)。

    4.6 触发某个formControlName

        let formControl = this.profileForm.get(&#39;firstName&#39;);
        formControl.updateValueAndValidity();

    更多编程相关知识,请访问:编程视频!!

    위 내용은 각도의 형태에 대한 깊은 이해(반응형 및 템플릿 기반)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제