# Day30 【牙起來】 表單(Form)初始化 - Angular 常見Angular的表單分為兩大類: * Dynamic Form 動態表單 * Reactive Form 響應式表單 ## Dynamic Form 動態表單 --- 在開始之前,首先先產生一個`user-input`讓使用者可以輸入資料的元件 > ng g c user-input ## Reactive Form 響應式表單 首先修改`app.module.ts`,因為使用到響應式表單,需匯入`ReactiveFormsModule`模組 ```typescript= import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { UserInputComponent } from './user-input/user-input.component'; import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ declarations: [ AppComponent, UserInputComponent ], imports: [ BrowserModule, ReactiveFormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } ``` 在程式中新增`myForm`表單,由`FormGroup`包住`FormControl` `FormControl` 表單控制項,可以視作**表單欄位**,可以輸入欄位預設值 `FormGroup` 是表單群組,可以視作**一整個表單**,底下可包含多個表單欄位 修改 `user-input.component.ts` ```typescript= import { FormControl, FormGroup } from '@angular/forms'; ... export class UserInputComponent implements OnInit { myForm = new FormGroup({ name: new FormControl('勇者一號'), age: new FormControl(19), }); constructor() { } ngOnInit(): void { } getData() { console.log(this.myForm.get('name')?.value, this.myForm.get('age')?.value); } } ``` > * `FormGroup` > * `FormControl` > * `AbstractControl` > > 因以上的Form相關元素不是Service,而是**物件** > 所以使用時需透過`import`後`new`一個實例來產生新物件 > > ```typescript= > ... > import { FormGroup } from '@angular/forms'; > ... > > export class UserInputComponent implements OnInit { > > formGroup = new FormGroup({ > > }) > > ... > ``` > > **而非**以下注入服務的方式 > > ```typescript= > ... > export class UserInputComponent implements OnInit { > > constructor(public formGroup: FormGroup) { } > > ... > ``` 接著在樣板上新增`formControlName` 修改 `user-input.component.html` ```html= <form [formGroup]="myForm"> <div>名稱:<input type="text" formControlName="name"></div> <div>年紀:<input type="text" formControlName="age"></div> </form> <button (click)="getData()">印出資料</button> ``` 最後修改`app.component.html` ```html= <app-user-input></app-user-input> ``` 至此 `user-input` 元件可以告一個段落,可以開啟F12看效果 ### FormBuilder 表單生成器 與前面`FormControl`**物件**不同,`FormBuilder`一個便於產生物件的**服務** 首先一樣宣告`myForm`成員,但不賦予初始值而只給型別 引入`FormBuilder`服務,可以省去前面範例落落長的英文字,在表單欄位很多的時候非常好用 修改 `user-input.component.ts` ```typescript= import { FormBuilder, FormGroup } from '@angular/forms'; ... export class UserInputComponent implements OnInit { myForm: FormGroup; constructor(private fb: FormBuilder) { this.myForm = fb.group({ name: '勇者一號', age: 19, }); } ... ``` 或者在宣告成員的時候,使用constructor注入的`fb`服務, 直接創表單同時給予初始值 ```typescript= ... export class UserInputComponent implements OnInit { myForm = this.fb.group({ name: '勇者一號', age: 19, }); constructor(private fb: FormBuilder) { } ngOnInit(): void { } } ``` 可以達到與前面範例相同的效果 [property宣告 放construct內、外有何差異?](https://stackoverflow.com/questions/64436532/javascript-class-property-inside-vs-outside-constructor) 執行順序也相同,兩者無分先後 // TODO [`[formControl]` vs `formControlName`](https://stackoverflow.com/questions/40171914/what-is-the-difference-between-formcontrolname-and-formcontrol) 三種取值方法 ![](https://i.imgur.com/w9Pcq4e.png) ```typescript= console.log(this.searchForm.value['code'], '111') console.log(this.searchForm.get('code')?.value, '222') console.log(this.searchForm.getRawValue().code, '333') ```