Con lắng nghe sự kiện cha trong Angular 2


81

Trong tài liệu góc có chủ đề về việc lắng nghe các sự kiện trẻ em từ cha mẹ. Tốt rồi. Nhưng mục đích của tôi là một cái gì đó ngược lại !. Trong ứng dụng của tôi có 'admin.component' giữ chế độ xem bố cục của trang quản trị (menu thanh bên, thanh tác vụ, trạng thái, v.v.). Trong thành phần chính này, tôi đã định cấu hình hệ thống bộ định tuyến để thay đổi chế độ xem chính giữa các trang khác của quản trị viên. Vấn đề là để lưu những thứ sau khi thay đổi, người dùng nhấp vào nút lưu trong thanh tác vụ (được đặt trong admin.component) và thành phần con phải lắng nghe sự kiện nhấp chuột đó để thực hiện lưu nhân viên.


2
nghe có vẻ như phương pháp tốt nhất để làm điều này là sử dụng một dịch vụ và một người điều hành sự kiện có thể quan sát được.
zpul

Câu hỏi của bạn không quá khác với câu hỏi này: stackoverflow.com/questions/35560860/…
freethebees

@freethebees Có thể giải pháp giống nhau, nhưng hình dạng của vấn đề khác nhau và mục đích của tôi là tìm cách tiếp cận tốt nhất cho tình huống này.
Hamed Hamedi

Chúng tôi sẽ không thiết lập một dịch vụ cho một sự kiện được chuyển đến một thành phần con.
Ben Racicot

Câu trả lời:


98

Tôi nghĩ rằng tài liệu này có thể hữu ích cho bạn:

Trên thực tế, bạn có thể tận dụng một chủ đề / quan sát được mà cha mẹ cung cấp cho con cái. Đại loại như vậy:

@Component({
  (...)
  template: `
    <child [parentSubject]="parentSubject"></child>
  `,
  directives: [ ChildComponent ]
})
export class ParentComponent {
  parentSubject:Subject<any> = new Subject();

  notifyChildren() {
    this.parentSubject.next('some value');
  }
}

Thành phần con có thể chỉ cần đăng ký chủ đề này:

@Component({
  (...)
})
export class ChildComponent {
  @Input()
  parentSubject:Subject<any>;

  ngOnInit() {
    this.parentSubject.subscribe(event => {
      // called when the notifyChildren method is
      // called in the parent component
    });
  }

  ngOnDestroy() {
    // needed if child gets re-created (eg on some model changes)
    // note that subsequent subscriptions on the same subject will fail
    // so the parent has to re-create parentSubject on changes
    this.parentSubject.unsubscribe();
  }

}

Nếu không, bạn có thể tận dụng dịch vụ được chia sẻ có chứa chủ đề như vậy theo cách tương tự ...


Lệnh gọi lại trong thành phần con của tôi sẽ không chạy trừ khi thành phần mẹ phát đi giá trị tiếp theo từ bên trong ngInit. Tại sao lại như vậy?
cjsimon

4
Có lợi thế nào khi sử dụng phương pháp này so với ViewChild không?
sunnyiitkgp

Mặc dù nó trông chuyên nghiệp hơn, nhưng sau khi dành vài giờ để thử nghiệm trong tình huống của tôi, tôi không thể gặp rắc rối với UnsubscribeErrors khi thêm / xóa các phần tử con (và do đó hủy đăng ký khỏi chủ đề). Vì vậy, bằng TimeBoxing, tôi đã tìm được câu trả lời đơn giản hơn nhiều về @StephenPaul. Dù sao, cảm ơn vì câu trả lời và có lẽ tôi không có thư viện rxjs đủ tốt ngay bây giờ để hiểu đầy đủ về nó và thực hiện các điều chỉnh phù hợp (bổ sung) cho ví dụ của bạn để nó hoạt động hoàn hảo.
Bernoulli IT

115

Vì lợi ích của hậu thế, tôi chỉ nghĩ rằng tôi sẽ đề cập đến giải pháp thông thường hơn cho việc này : Đơn giản chỉ cần lấy một tham chiếu đến ViewChild sau đó gọi trực tiếp một trong các phương thức của nó.

@Component({
  selector: 'app-child'
})
export class ChildComponent {

  notifyMe() {
    console.log('Event Fired');
  }
}

@Component({
  selector: 'app-parent',
  template: `<app-child #child></app-child>`
})
export class ParentComponent {

  @ViewChild('child')
  private child: ChildComponent;

  ngOnInit() {
    this.child.notifyMe();
  }
}

3
Nó bị treo ngay sau khi tôi nhập các thành phần cha mẹ ... Cannot read property 'notifyMe' of undefined.
người dùng tốt bụng

1
Đã sử dụng giải pháp rất đơn giản này so với giải pháp cảm giác chuyên nghiệp hơn của @ThierryTemplier (xem nhận xét của tôi ở đó).
Bernoulli IT

2
@BernoulliIT bạn làm cho một điểm tốt. Tôi cho rằng vào cuối ngày họ hoàn thành được điều tương tự. Giải pháp của tôi sử dụng ít mã hơn. Giải pháp của anh ấy có nghĩa là thành phần mẹ không phải đưa thành phần con vào để gửi thông báo cho nó. RXJS rất tuyệt, nhưng tôi thường thấy lạm dụng nó trong các dự án Angular. Mọi người nghĩ nó là 'viên đạn bạc' hay gì đó. Nó thực sự có thể khiến mọi thứ trở nên phức tạp hơn nhiều so với mức cần thiết. Nhìn vào bình luận của anh ấy bên trong ngOnDestroy()phương pháp của anh ấy . Đó là cách quá mù mờ theo như tôi nghĩ. Đó chỉ là một lỗi đang chờ xảy ra IMHO.
Stephen Paul

1
"Hãy xem nhận xét của anh ấy bên trong phương thức ngOnDestroy () của anh ấy." Tôi nghĩ đó chính xác là những gì tôi đã "chịu đựng" khi thử cách tiếp cận đó, sau đó tôi bị mắc kẹt và không có nhiều thời gian để tìm hiểu thêm (cho một dự án thương mại mà tôi đang làm). Mặc dù nó "làm hỏng" trái tim chuyên nghiệp của tôi một chút;)
Bernoulli IT

1
Cảm ơn @StephenPaul, đối với tôi Parent Calls một phương pháp Viewchild rất hay, nhưng câu trả lời của bạn đã giúp tôi đạt được định mệnh của mình!
MKJ

13

Có thể có một cách tiếp cận xương trần hơn ở đây nếu tôi hiểu đúng câu hỏi. Giả định -

  • OP có một nút lưu trong thành phần mẹ
  • Dữ liệu cần được lưu trong các thành phần con
  • Tất cả dữ liệu khác mà thành phần con có thể cần có thể được truy cập từ các dịch vụ

Trong thành phần mẹ

<button type="button" (click)="prop1=!prop1">Save Button</button>
<app-child-component [setProp]='prop1'></app-child-component>

Và ở đứa trẻ ..

prop1:boolean;
  @Input()
  set setProp(p: boolean) {
    // -- perform save function here
}

Điều này chỉ đơn giản là gửi nút bấm đến thành phần con. Từ đó thành phần con có thể lưu dữ liệu một cách độc lập.

CHỈNH SỬA: nếu dữ liệu từ mẫu mẹ cũng cần được chuyển cùng với việc nhấp vào nút, điều đó cũng có thể thực hiện được với cách tiếp cận này. Hãy cho tôi biết nếu trường hợp đó xảy ra và tôi sẽ cập nhật các mẫu mã.


0

Đối với những người đang nhận được Cannot read property 'notifyMe' of undefined

Hãy thử gọi phương thức bên trong ngAfterViewInit()intead ofngOnInit()

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.