Angular ViewChild và ViewChildren

Bài viết này tập trung vào việc tìm hiểu cách sử dụng @ViewChild@ViewChildren bên trong các Angular component. Tôi sẽ xem xét làm thế nào để sử dụng hiệu quả các chức năng này để đạt được kết quả mong muốn của bạn. Một phần tử có thể có được một tham chiếu đến một element hoặc sử dụng derective để chúng ta có thể truy cập nó trực tiếp. Derective có thể là directive riêng của Angular hoặc một custom directive do người dùng định nghĩa. Đôi khi chúng ta có thể yêu cầu truy cập trực tiếp vào element hoặc component và thao tác các thuộc tính của element hoặc component. Điều này bằng cách nào đó giống như nhận một DOM element bằng cách sử dụng JavaScript và cập nhật thuộc tính và hành vi của DOM element.

1. Làm việc với Angular ViewChild

@ViewChild có thể được sử dụng để lấy tham chiếu của DOM element được hiển thị bên trong một Angular component. Chúng ta có thể sử dụng tham chiếu của DOM element để thao tác các thuộc tính phần tử. Để có được element, chúng ta cần sử dụng selector.

// Accessing DOM element with JavaScript
let domReference = document.getElementById("someElement");

// Access DOM element using Angular @ViewChild
@ViewChild("someElement") domReference;

Ở trên là mã để truy cập phần tử DOM bằng cách sử dụng JavaScript đơn giản hoặc Angular @ViewChild. Sử dụng JavaScript, chúng ta có thể sử dụng selector để trích xuất element. Để sử dụng selector như trên ta cần một phần tử có id tương tự như:

<div id=”someElement” >Sample Code</div>

Dưới đây là một phần tử div có template reference được đánh dấu là someElement. Template reference bắt đầu bằng #. Với Angular, chúng ta có thể truy cập các phần tử bằng cách sử dụng các template reference này. Element reference có thể được truy xuất bằng cách sử dụng @ViewChild và template-reference được chỉ định tương ứng. Ví dụ như:

<div #someElement>Sample Code</div>

Khi nào chúng ta có thể sử dụng ViewChild Variable?

Tham chiếu đến biến @ViewChild được gán sau khi View được khởi tạo. Angular cung cấp 1 life-cycle Hook gọi là ngAfterViewInit. Khi View is được khởi tạo và render, @ViewChild sau đó có thể truy cập phần tử bằng template reference. Nó cung cấp quyền truy cập vào element/derective. Ví dụ:

@Component({
  selector: 'accessing-template-reference',
  template: '<div><input type="text" #someElement />'
})
export class HeroListComponent implements OnInit {
  @ViewChild("someElement") domReference;
  
  ngAfterViewInit(): void {
    this.domReference.nativeElement.focus();
  }
}

Trong đoạn mã trên, các điểm sau cần được xem xét:

  1. Chúng ta có thể truy cập phần tử đầu vào có template reference “someElement” sử dụng ViewChild
  2. ViewChild element domReference sẽ chỉ nhận được quyền truy cập vào DOM element sau khi nó được rendered.
  3. @ViewChild có thể cho phép người dùng truy cập native DOM element của View được hiển thị. Sử dụng DOM reference, chúng ta có thể truy cập và sửa đổi các thuộc tính DOM như manipulating style, innerText, value và các thuộc tính khác liên quan đến một element được tham chiếu.

Truy cập Element sử dụng Angular Directive

Chúng ta có thể sử dụng các Angular directives như NgModel với @ViewChild. Hãy cùng tôi tìm kiếm các yêu cầu và sử dụng các use case để truy cập các Angular directives bằng cách sử dụng @ViewChild.

@Component({
  selector: 'accessing-template-reference',
  template: `
    <div>
      <input type="text" id="userName" [(ngModel)]="userName" />
    </div>
  `
})
export class HeroListComponent implements OnInit {
  @ViewChild(NgModel) userNameReference: NgModel;
  
  ngAfterViewInit(): void {
    this.userNameReference.valueChanges.subscribe(
      () => { this.executeOtherFunction() }
    )
  }
}

Tôi có thể truy cập NgModel directive bên trong @ViewChild và đăng ký thay đổi giá trị. Trên đây là code, nơi tôi đang cố gắng truy cập một element bằng cách sử dụng NgModel Angular. Phần tử với ID userName đang có lệnh NgModel được thêm vào nó. Sử dụng @ViewChild, chúng tôi sẽ theo dõi các thay đổi đối với bất kỳ cập nhật giá trị nào bên trong phần tử đầu vào.

Tôi nhận được tham chiếu đến phần tử đầu vào Cấu trúc dữ liệu NgModel của element, và sử dụng tham chiếu, chúng tôi có thể truy cập thông tin trạng thái của nó, như liệu nó đã được sửa đổi hay giá trị hợp lệ hay không.

Nó có thể được truy cập bên trong ngAfterViewInit life cycle. Chúng ta có quyền truy cập vào tất cả các thông tin state. Nó cũng cung cấp thông tin về bất kỳ cập nhật property. Tài liệu tham khảo này là chỉ đọc. Nó cho phép chúng tôi truy cập để có thể quan sát và chúng tôi có thể sử dụng điều này có thể quan sát được để đăng ký giá trị có thể quan sát được.

2. Angular ViewChildren

Làm việc với @ViewChildren tương tự như @ViewChild, nhưng sự khác biệt giữa hai loại này là @ViewChildren cung cấp một danh sách cácelement references thay vì trả về mộtreference duy nhất. Nó được sử dụng để reference nhiều element. Sau đó chúng ta có thể lặp lại danh sách các phần tử element referenced bởi biến. Các selector sau có thể được sử dụng với @ViewChildren:

  1. Chúng ta có thể sử dụng ViewChildren với Angular directives như NgModel

Chúng ta có thể sử dụng các directives sẵn có như NgModel với ViewChild. Nó sẽ đưa ra danh sách tất cả các elements có NgModel kèm theo.

@Component({
  selector: 'accessing-template-reference',
  template: `
    <div>
      <input type="text" [(ngModel)]="userName" />
      <input type="text" [(ngModel)]="userAge" />
      <input type="text" [(ngModel)]="userDesignation" />
    </div>
  `
})
export class HeroListComponent implements OnInit {
  @ViewChildren("NgModel") domReference: QueryList<NgModel>;
  
  ngAfterViewInit(): void {
    console.log("Element List: " + this.domReference.length);
  }
}

Trên đên là code trích xuất phần tử bằng cách sử dụng lệnh Angular directive NgModel . Tất cả các components có chứa Angular directive được chỉ định có thể được truy xuất và đánh giá thêm.

  1. Truy cập elements sử dụng child components

Tương tự như việc sử dụng các directives với @ViewChildren, chúng ta có thể sử dụng tên component con để truy cập các phần tử bằng @ViewChildren. Điều này chỉ cần chúng ta có một số child component (ví dụ user-details) bên trong main component chúng ta. Hãy xem ví dụ sau:

@Component({
  selector: 'accessing-template-reference',
  template: `
    <div>
      <user-details [userId]="firstUser"></user-details>
      <user-details [userId]="secondUser"></user-details>
      <user-details [userId]="thirdUser"></user-details>
    </div>
  `
})
export class HeroListComponent implements OnInit {
  @ViewChildren("UserDetailComponent") userDetailReferences: QueryList<NgModel>;
  
  ngAfterViewInit(): void {
    console.log("Element List: " + this.userDetailReferences.length);
  }
}

Đoạn code trên nhận được danh sách tất cả các child-component reference có trong parent component. Sau đó chúng ta có thể sử dụng các tham chiếu này để thực hiện custom logic. Sau đó, chúng ta hoàn toàn có thể sử dụng danh sách này để hoàn thành các further tiếp theo. 3. Sử dụng template-reference variables

Nhiều element bên trong components có thể chứa cùng một template reference. Nếu chúng ta sử dụng template reference ở nhiều nơi, chúng ta sẽ nhận được danh sách reference của tất cả các element được tham chiếu bởi cùng template-reference variable trong template.

@Component({
  selector: 'accessing-template-reference',
  template: `
    <div>
      <input type="text" #applicationInfo />
      <input type="text" #applicationInfo />
      <input type="text" #applicationInfo />
    </div>
  `
})
export class HeroListComponent implements OnInit {
  @ViewChildren("applicationInfo") applicationInfo: QueryList<NgModel>;
  
  ngAfterViewInit(): void {
    console.log("Element List: " + this.applicationInfo.length);
  }
}

Đoạn code trên chứa nhiều element có cùng template-reference variable. @ViewChildren sẽ cho phép người dùng truy cập tất cả các element tham chiếu đến template reference applicationInfo.

  1. Truy cập đến nhiều template-reference variables

Selector có thể là một tập hợp template references. Chúng ta có thể chỉ định nhiều template references. Tất cả các element có chứa template reference được chỉ định trong danh sách được lấy từ component.


@Component({
  selector: 'accessing-template-reference',
  template: `
    <div>
      <input type="text" #userName />
      <input type="text" #userAge />
      <input type="text" #userDesignation />
    </div>
  `
})
export class HeroListComponent implements OnInit {
  @ViewChildren("userName, userAge, userDesignation") userInfoReference: QueryList<NgModel>;
  
  ngAfterViewInit(): void {
    console.log("Element List: " + this.userInfoReference.length);
  }
}

Trong đoạn code trên, chúng ta sẽ thêm danh sách các template-reference bên trong @ViewChildren. Tất cả các component có chứa tham chiếu element có trong danh sách được lấy ra và có thể được truy cập với tên biến.

3. ViewChild và Child Components

ViewChild và ViewChildren có thể được sử dụng để truy cập các thuộc tính và phương thức của child-element. Sử dụng ViewChild và ViewChildren, chúng ta có thể nhận được tham chiếu của child-element, phần tiếp tục cung cấp quyền truy cập vào tất cả các thuộc tính và phương thức. Điều này có thể cho phép một parent-component truy cập vào child-component và cho phép giao tiếp giữa chúng. Chúng ta hãy nhìn vào code để hiểu rõ hơn về khái niệm này:

@Component({
  selector: 'child-component',
  template: `
    <div>
      <input type="text" [(ngModel)]="userName" />
    </div>
  `
})
export class ChildComponent implements OnInit {

 public userName: string;
  
  updateUserName(): void {
    this.userName = "Mayank"
  }
}

Đoạn code trên chứa một child-element đơn giản, có thuộc tính userName và hàm updateUserName, được quy định để cập nhật thuộc tính userName của element.

Bây giờ, hãy để thêm một component mới sẽ hoạt động như một ParentComponent cho ChildComponent ở trên. Chúng ta sẽ xem xét code để truy cập các thuộc tính và phương thức của thành phần con từ thành phần cha mẹ bằng cách sử dụng @ViewChild. Hãy nhìn vào code dưới đây.

@Component({
  selector: 'child-component',
  template: `
    <div>
      <b>This is the Parent Component Accessing Child Component</b>
      <child-component #userInformation></child-component>
      <input type="button" value="Update User Name" (click)="updateUserData()" />
    </div>
  `
})
export class ParentComponent implements OnInit {
  @ViewChild("userInformation") childComponentReference: any;
  
  updateUserData() {
    
    // Accessing Property of Child Component
    this.childComponentReference.userName = "Updated Name";
    
    // Accessing Functions of Child Component
    this.childComponentReference.updateUserName();
  }
}

Đoạn code trên đại diện cho ParentComponent. Trong mẫu được chỉ định cho thành phần cha, chúng ta có một thành phần con được thêm vào.

Thành phần con được đánh dấu bằng mộttemplate-reference variable. Chúng ta có thể sử dụng tham chiếu mẫu này để truy cập các thuộc tính và biến của thành phần con.

@ViewChild(“userInformation”) childComponentReference: any;

@ViewChild có thể được sử dụng để truy cập thành phần con có template reference userInformation, đại diện cho thành phần con. Sử dụng childComponentReference này, chúng ta có thể truy cập thêm các thuộc tính và gọi chức năng của thành phần con, như được sử dụng ở trên.

Kết luận

Tôi hi vọng bạn có thể sử dụng nội dung bài viết để phục vụ cho công việc của bạn một cách hiệu quả nhất, cảm ơn bạn đã theo dõi, hãy để lại nhận xét nếu bạn có điều thắc mắc. Xin trân trọng cảm ơn. Bài viết tham khảo: https://medium.com/better-programming/angular-viewchild-and-viewchildren-fde2d252b9ab