Angular Reactive Forms: Cách sử dụng FormArray

Tram Ho

Trong bài viết này chúng ta sẽ tìm hiểu khi nào và cách sử dụng FormArray, cả trong Component và trong Template, ngoài ra chúng ta sẽ xem cách để custom validation cho nó.

Lưu ý: Để bài viết đem lại hiệu quả nhất, thì hãy tự trang bị cho mình thêm 1 chút kiến thức cơ bản về FormGroupFormControl nhé.

Vì sao chúng ta cần sử dụng FormArray

Có thể bạn đã biết, khi chúng ta tạo một AbstractControl như FormGroup hay FormControl, chúng ta có thể sử dụng mảng như một giá trị. Ví dụ

Tuy nhiên, cách khai báo này sẽ gây khó khăn để sử dụng Angular API cho từng phần tử trong mảng, cũng như đồng bộ giá trị hay sử dụng API validate. Đó là khi ta cần dùng đến FormArray

FormArray là gì

FormArray có trách nhiệm quản lý một tập hợp các AbstractControl, có thể là FormGroup, FormControl hoặc FormArray khác.

Cũng giống như FormGroup, nhóm các đối tượng AbstractControl trong một đối tượng, FormArray cũng làm tương tự nhưng trong một mảng. Angular có các API cụ thể để giúp bạn quản lý tập hợp này mà chúng ta sẽ nói rõ hơn ở phần sau. Giờ hãy xem cách sử dụng nó.

Làm việc với FormArray

Giả sử chúng ta muốn hiển thị một form mà người dùng có thể thêm, sửa, xóa từ một danh sách kĩ năng

Chúng ta tạo một FormArray với giá trị khởi tạo là một mảng rỗng. Giờ hãy xem các thuộc tính của skills:

Giống như FormControl hay FormGroup, FormArray cũng được kế thừa từ class AbstractControl, nên cũng có nhiều thuộc tính giống nhau, như valid, dirty, disabled,… Ngoài ra, nó có thêm 1 thuộc tính controls để chứa mảng các phần tử của AbstractControl.

GIờ hãy thêm 1 skill:

Mỗi lần gọi đến phương thức addSkill, chúng ta sẽ thêm 1 FormControl mới vào mảng controls. Giờ hãy sử dụng nó trong template. Đầu tiên, chúng ta cần một vòng lặp cho thuộc tính controls của FormArray:

Giờ, chúng ta thêm vào mỗi control directive formControl để đồng bộ mỗi control với phần tử tương ứng.


Thật đơn giản phải không. Giờ hãy thử vài phương thức khác mà chúng ta có thể sử dụng luôn:

  • removeAt(index): Phương thức này nhận vào index và loại bỏ AbstractControl tương ứng.

  • insert(index, AbstracControl): trái ngược với removeAt(), nó thêm 1 AbstractControl mới vào vị trí index trong mảng controls

  • clear(): loại bỏ tất cả phần tử trong mảng

  • setControl(index, AbstractControl): không giống với phương thức insert, nó thay thế control đã có bằng AbstractControl truyền vào. Trong ví dụ dưới đây, nó được sử dụng trong phương thức replace(), để thay thế control đầu tiên bằng một cái mới vừa tạo.

  • at(index): trà về AbstracControl ở vị trí index của mảng. Trong ví dụ dưới đây sẽ trả về control đầu tiên

Thêm FormGroup

Trong phần trước, chúng ta đã biết cách để quản lý tập hợp FormControls, giờ hãy xem cách để quản lý đối tượng FormGroup trong FormArray:

Thay vì truyền vào FormControl, chúng ta truyền vào FormGroup. Còn trong template:

Chúng ta chạy vòng lặp mỗi control, như trong ví dụ là FormGroup, và truyền nó vào directive formGroup. Tiếp đó chỉ là đồng bộ dữ liệu bằng cách quen thuộc – truyền tên control vào directive formControlName.

Sử dụng FormArray trong FormGroup

Giờ khi đã quen với những điều cơ bản, hãy xem xét một số ví dụ thực tế hơn, trong đó ta thường sử dụng FormGroup bên trong FormArray

Không có gì đặc biệt ở đây, chỉ là tạo một FormGroup bình thường. Hãy nhìn vào template

Chúng ta thêm directive formGroup vào form, và bên trong, chúng ta liên kết control name thông qua directive formControlName. Tương tự, để liên kết với các control của FormArray, chúng ta cần làm theo 3 bước sau:

Đầu tiên, ta cần thêm formArrayName vào phần tử cha, nó giống như chạy user.get(skills).

Tiếp theo, giống như ví dụ trước, chúng ta cần chạy vòng lặp các control trong FormArray:

Trước khi đến với bước cuối cùng, hãy định nghĩa thuộc tính skills trong component. Theo cách truyền thống là sử dụng hàm getter để tham chiếu tới control FormArray từ thằng cha FormGroup.

Hoặc ta có thể khai báo nó như 1 biến

Giờ là bước cuối cùng:

Directive formControlName lấy tên của control mà chúng ta muốn đồng bộ với phần tử của form. Khi làm việc với FormGroup, chúng ta truyền vào tên key của đối tượng, ví dụ:

Nó sẽ tìm kiểu user.get('name'). Nhưng trong trường hợp này, nó là FormArray nên tên sẽ là index. Trong JS, mảng là một đối tượng đặc biệt, có key là số (dựa trên index của chúng), vì vậy code sẽ giống như thế này: user.get('skills')[index] => FormControl.

Giờ hãy xem quy trình tương tự với FormArray chứa tập hợp các FormGroup:

FormArray giờ chứa FormGroup nên chúng ta cần dùng directive formGroupName: user.get('skills')[index] => FormGroup.

Khi chúng ta sử dụng formControlName, nó sẽ tìm kiếm ControlContainer cha gần nhất, trong trường hợp này là đối tượng FormGroup cha hiện tại.

FormArray Validation

Như đã đề cập từ đầu, ta có thể áp dụng validation vào mỗi AbstractControl như chúng ta thường làm:

Trong trường hợp này, tính hợp lệ của FormArray dựa trên tính hợp lệ của các AbstractControl. Vì vậy, chỉ cần có 1 AbstractControl không hợp lệ, tính hợp lệ của FormArray sẽ được set là false.

Chúng ta cũng có thể áp dụng validate ở trực tiếp FormArray, ví dụ cần validate kích thước mảng:

Như với bất kì AbstractControl nào, chúng ta có thể truyền hàm validate, trong trường hợp này nó sẽ nhận vào FormArray mỗi lần thay đổi, và trả về null nếu mảng hợp lệ, ngược lại, trả về một đối tượng cho biết cụ thể lỗi.

FormArray với Server Data

Hãy tóm tắt lại mọi thứ bằng một ví dụ khá phổ biến là chúng ta cần tạo các control của FormArray từ dữ liệu server trả về.

Trong trường hợp này chúng ta không thể sử dụng patchValue() hay setValue(), vì các phương thức này dùng để cập nhật giá trị của các controls đã tồn tại, trong khi các control tương ứng với dữ liệu trả về vẫn chưa được tạo. Thay vào đó, chúng ta cần tạo FormArray từ đầu và set giá trị cho từng controls

Trong trường hợp chúng ta đã có sẵn các control trong FormArray, chúng ta đơn giản chỉ cần tạo các control cần thêm, sau đó thêm nó vào mảng:

Bài viết khá đơn giản với những kiến thức cơ bản, hy vọng nó có ích với bạn, nếu có gì khó hiểu hãy comment để mình giúp bạn giải đáp nha! 

Nguồn: https://netbasal.com/angular-reactive-forms-the-ultimate-guide-to-formarray-3adbe6b0b61a

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo