Skip to main content

Effective Angularの第4章のまとめ

Effective Angular

Effective Angularの第3章のまとめ
の続編

4章:Building Forms Like a Pro
を読んだので調べたことをつらつらと書く


フォーム系
・テンプレート変数
#addExpenseFormはテンプレート変数
Viewchildで参照できる
https://qiita.com/Nkot117/items/21adf2c9828bc03f7ca8
https://www.digitalocean.com/community/tutorials/angular-viewchild-access-component-ja

<form #addExpenseForm="ngForm" (ngSubmit)="onSubmit()">
@ViewChild('addExpenseForm') form!: NgForm;

・FormGroup
これでデータが同期される

<form [formGroup]="addExpenseForm2">
    <input formControlName="description" type="text"/>
</form>
addExpenseForm2 = new FormGroup({
    description: new FormControl('Test'),
});

・デバック
jsonをかませばとりあえずなんでも出力される

{{expenseToAdd | json}}

・双方向バインディング

<input #description="ngModel" [(ngModel)]="expenseToAdd.description" type="text" id="description" name="description">
@Input() expenseToAdd: AddExpense = {
    description: '',
    amountExclVat: null,
    vatPercentage: null,
    date: null,
};

・jsonでフォームにデータを代入するする

export interface AddExpenseReactive {
  description?: string;
  amount?: {
    amountExclVat?: number;
    vatPercentage?: number;
  };
  date?: string[];
  tags?: string[];
}

addExpenseForm2 = new FormGroup({
    description: new FormControl('Test'),
    amount: new FormGroup({
        amountExclVat: new FormControl<number | null>(null),
        vatPercentage: new FormControl<number | null>(null),
    }),
    date: new FormControl<string[]>([]),
    tags: new FormArray<FormControl<string>>([]),
});

public set addExpense2(value: AddExpenseReactive) {
    this.addExpenseForm2.patchValue(value);
}

 

validation
・デフォルト
maxが100なので100超えるとエラーになる

<input #amount="ngModel" [max]=100 [(ngModel)]="expenseToAdd.amountExclVat" type="number" id="amountExclVat" name="amountExclVat">
{{amount?.errors ?? "noerror" | json}}

touchedをつけると一度でもタッチした後のみエラーになる
maxのときだけ以下のエラーがでる

<span *ngIf="addExpenseForm.touched && amount.hasError('max')">this field is required</span>

・カスタムバリデーター

description: new FormControl('', [
    Validators.required,
    maxWordCountValidator(3),
]),
export function maxWordCountValidator(maxWords: number): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const wordCount = control?.value?.trim().split(' ').length;
    return wordCount > maxWords ? { maxWordCount: { count: wordCount } } : null;
  };
}

 

エラー
・Can’t bind to ‘formGroup’ since it isn’t a known property of ‘form’.ngtsc(-998002)
ReactiveFormsModuleをimportする
https://stackoverflow.com/questions/39152071/cant-bind-to-formgroup-since-it-isnt-a-known-property-of-form

・ERROR RuntimeError: NG01053: formGroupName must be used with a parent formGroup directive. You’ll want to add a formGroup
ERROR RuntimeError: NG01053: formGroupName must be used with a parent formGroup directive. You’ll want to add a formGroup
directive and pass it an existing FormGroup instance (you can create one in your class).
formにFormGroupを設定し、残りの要素はformのタグの中に入れると解消する

・ERROR Error: Cannot find control with name: ‘0’
trackbyを指定する必要がある
https://kakkoyakakko2.hatenablog.com/entry/2018/12/29/143957

<div class="form-field" *ngFor="let item of tags.controls; index as i;trackBy: trackByIndex">
trackByIndex(index: number, _: any) {
    return index;
}

 

Effective Angular

関連記事:

Pocket