Làm thế nào để phát ra một sự kiện từ cha mẹ sang con?


111

Tôi hiện đang sử dụng Angular 2. Thông thường chúng tôi sử dụng @Output() addTab = new EventEmitter<any>();và sau đó addTab.emit()để phát ra một sự kiện cho thành phần mẹ.

Có cách nào chúng ta có thể làm điều đó, từ cha mẹ đến con cái?


2
Chỉ cần thay đổi giá trị của một biểu thức được truyền dưới dạng Đầu vào cho thành phần con và thành phần con sẽ nhận được nó (và được thông báo bởi ngOnChanges). Bạn cũng có thể tạo ra một sự kiện bằng cách sử dụng một dịch vụ chia sẻ có một Observable.
JB Nizet

Câu trả lời:


192

Sử dụng RxJs , bạn có thể khai báo một Subjecttrong thành phần mẹ của mình và chuyển nó như là Observablethành phần con, thành phần con chỉ cần đăng ký thành phần này Observable.

Thành phần chính

eventsSubject: Subject<void> = new Subject<void>();

emitEventToChild() {
  this.eventsSubject.next();
}

HTML gốc

<child [events]="eventsSubject.asObservable()"> </child>    

Thành phần con

private eventsSubscription: Subscription;

@Input() events: Observable<void>;

ngOnInit(){
  this.eventsSubscription = this.events.subscribe(() => doSomething());
}

ngOnDestroy() {
  this.eventsSubscription.unsubscribe();
}

13
Ngoài ra, dữ liệu có thể được chuyển cùng với sự kiện bằng cách sử dụng phương pháp này. Giống như, this.eventsSubject.next({data});ở cha mẹ, sau đó this.events.subscribe(({data}) => doSomething(data));ở con cái.
vince

2
Tôi đã chỉnh sửa câu trả lời tuyệt vời này để thêm hủy đăng ký. 1
Umar Farooq Khawaja

1
Có thể là một câu hỏi dành cho người mới bắt đầu ở đây: Tại sao lại chuyển đổi eventsSubjectthành một Đối tượng có thể quan sát thay vì chỉ đăng ký nó như một Chủ thể?
Justin Morgan,

11
Chuyển đổi sự kiện Đối tượng thành có thể quan sát được, ngăn thành phần con gọi next ().
BlueNC

2
Cảm ơn giải pháp này, NÓ hoạt động nhưng tôi gặp lỗi trong bảng điều khiển: "core.js: 6185 LỖI LoạiError: Không thể đọc thuộc tính 'subscribe' của undefined" Lỗi chỉ đến các sự kiện.subscribe () trong ngOnInit của thành phần con: "this.eventsSubscription = this.events.subscribe (() => doSomething ());" Tôi đang sử dụng các phiên bản: "@ angle / cli": "~ 9.1.0" và "rxjs" : "~ 6.5.4"
Eduardo

72

Theo như tôi biết, có 2 cách tiêu chuẩn để bạn có thể làm điều đó.

1. @Input

Bất cứ khi nào dữ liệu trong phụ huynh thay đổi, trẻ sẽ được thông báo về điều này trong phương thức ngOnChanges. Đứa trẻ có thể hành động trên đó. Đây là cách tương tác tiêu chuẩn với một đứa trẻ.

Parent-Component
public inputToChild: Object;

Parent-HTML
<child [data]="inputToChild"> </child>       

Child-Component: @Input() data;

ngOnChanges(changes: { [property: string]: SimpleChange }){
   // Extract changes to the input property by its name
   let change: SimpleChange = changes['data']; 
// Whenever the data in the parent changes, this method gets triggered. You 
// can act on the changes here. You will have both the previous value and the 
// current value here.
}
  1. Khái niệm dịch vụ chia sẻ

Tạo một dịch vụ và sử dụng một dịch vụ có thể quan sát được trong dịch vụ được chia sẻ. Đứa trẻ đăng ký nó và bất cứ khi nào có thay đổi, đứa trẻ sẽ được thông báo. Đây cũng là một phương pháp phổ biến. Khi bạn muốn gửi một thứ gì đó khác với dữ liệu bạn chuyển làm đầu vào, điều này có thể được sử dụng.

SharedService
subject: Subject<Object>;

Parent-Component
constructor(sharedService: SharedService)
this.sharedService.subject.next(data);

Child-Component
constructor(sharedService: SharedService)
this.sharedService.subject.subscribe((data)=>{

// Whenever the parent emits using the next method, you can receive the data 
in here and act on it.})

Tôi đã thử phương pháp đầu tiên và nó hoạt động tốt cho đến một thời điểm nào đó và sau đó tôi nhận được thông báo lỗi cho biết Giá trị đã thay đổi ngay bây giờ, trước đó là sai và bây giờ là đúng. Nó không cho tôi bất kỳ lời giải thích nào khác ngoài điều này.
code1

2
Với ý bạn là lỗi ExpressionChangedAfterItHasBeenCheckedErcked, lỗi này sẽ không xuất hiện trong chế độ sản xuất.
user1337

<child [data]="inputToChild"> </child>có lẽ nên <child [data]="(inputToChild)"> </child>nhận thay đổi
pmc 27/02/19

28

Trong một thành phần mẹ, bạn có thể sử dụng @ViewChild () để truy cập vào phương thức / biến của thành phần con.

@Component({
  selector: 'app-number-parent',
  templateUrl: './number-parent.component.html'
})
export class NumberParentComponent {
    @ViewChild(NumberComponent)
    private numberComponent: NumberComponent;
    increase() {
       this.numberComponent.increaseByOne();
    }
    decrease() {
       this.numberComponent.decreaseByOne();
    }
} 

Cập nhật:

Angular 8 trở đi -

@ViewChild(NumberComponent, { static: false })

4
Điều này có vẻ sạch hơn so với làm việc với các vật thể quan sát. Hạn chế là đứa trẻ phải được xem. Ví dụ: nếu đứa trẻ được tải với định tuyến, điều này sẽ không numberComponentthành công undefined.
Shy Agam

1
đây có phải là một thực hành tốt? tôi đồng ý với thực tế là nó sạch hơn những thứ có thể quan sát được, nhưng tôi nghi ngờ về việc thao túng các biến của đứa trẻ từ cha mẹ. Dù sao, nó hoạt động rất tốt cho nhu cầu của tôi, Cảm ơn!
Takatalvi

1
Đây là một mẹo hay. Có vẻ như @ViewChild đã được thay đổi trong Angular 8, hoặc ít nhất tôi phải chỉ định các tùy chọn của ViewChild. Tôi đã sử dụng cái này trong trường hợp của mình: @ViewChild (Other, {static: false}) private otherComponent: Other;
Tore Aurstad

8

Sử dụng trình trang trí @Input () trong thành phần con của bạn để cho phép cha mẹ liên kết với đầu vào này.

Trong thành phần con, bạn khai báo nó như sau:

@Input() myInputName: myType

Để liên kết một thuộc tính từ cấp độ gốc đến cấp độ con, bạn phải thêm vào mẫu các dấu ngoặc vuông liên kết và tên của đầu vào của bạn giữa chúng.

Thí dụ :

<my-child-component [myChildInputName]="myParentVar"></my-child-component>

Nhưng hãy cẩn thận, các đối tượng được truyền dưới dạng tham chiếu, vì vậy nếu đối tượng được cập nhật trong phần con, var của cha sẽ quá cập nhật. Điều này đôi khi có thể dẫn đến một số hành vi không mong muốn. Với các loại chính, giá trị được sao chép.

Để tiếp tục đọc phần này:

Tài liệu: https://angular.io/docs/ts/latest/cookbook/component-communication.html


1

Trong phạm vi phụ huynh, bạn có thể giới thiệu trẻ bằng @ViewChild. Khi cần thiết (tức là khi sự kiện sẽ được kích hoạt), bạn chỉ có thể thực thi một phương thức trong phần con từ phương thức chính bằng cách sử dụng tham chiếu @ViewChild.

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.