Alternatif lain.
OP menanyakan cara untuk menggunakan panggilan balik. Dalam hal ini ia merujuk secara khusus ke fungsi yang memproses suatu peristiwa (dalam contohnya: peristiwa klik), yang akan diperlakukan sebagai jawaban yang diterima dari @serginho menyarankan: dengan @Output
danEventEmitter
.
Namun, ada perbedaan antara panggilan balik dan peristiwa: Dengan panggilan balik komponen anak Anda dapat mengambil beberapa umpan balik atau informasi dari orang tua, tetapi suatu peristiwa hanya dapat menginformasikan bahwa sesuatu terjadi tanpa mengharapkan umpan balik.
Ada kasus penggunaan di mana umpan balik diperlukan, mis. dapatkan warna, atau daftar elemen yang perlu ditangani oleh komponen. Anda dapat menggunakan fungsi terikat seperti yang disarankan beberapa jawaban, atau Anda dapat menggunakan antarmuka (itu selalu merupakan preferensi saya).
Contoh
Misalkan Anda memiliki komponen generik yang beroperasi di atas daftar elemen {id, name} yang ingin Anda gunakan dengan semua tabel database Anda yang memiliki bidang ini. Komponen ini harus:
- mengambil serangkaian elemen (halaman) dan menunjukkannya dalam daftar
- bolehkan hapus elemen
- informasikan bahwa suatu elemen telah diklik, sehingga orang tua dapat mengambil beberapa tindakan.
- bolehkan mengambil kembali elemen halaman berikutnya.
Komponen Anak
Dengan menggunakan penjilidan normal kita membutuhkan 1 @Input()
dan 3 @Output()
parameter (tetapi tanpa umpan balik dari orang tua). Ex. <list-ctrl [items]="list" (itemClicked)="click($event)" (itemRemoved)="removeItem($event)" (loadNextPage)="load($event)" ...>
, tetapi membuat antarmuka, kita hanya perlu satu @Input()
:
import {Component, Input, OnInit} from '@angular/core';
export interface IdName{
id: number;
name: string;
}
export interface IListComponentCallback<T extends IdName> {
getList(page: number, limit: number): Promise< T[] >;
removeItem(item: T): Promise<boolean>;
click(item: T): void;
}
@Component({
selector: 'list-ctrl',
template: `
<button class="item" (click)="loadMore()">Load page {{page+1}}</button>
<div class="item" *ngFor="let item of list">
<button (click)="onDel(item)">DEL</button>
<div (click)="onClick(item)">
Id: {{item.id}}, Name: "{{item.name}}"
</div>
</div>
`,
styles: [`
.item{ margin: -1px .25rem 0; border: 1px solid #888; padding: .5rem; width: 100%; cursor:pointer; }
.item > button{ float: right; }
button.item{margin:.25rem;}
`]
})
export class ListComponent implements OnInit {
@Input() callback: IListComponentCallback<IdName>; // <-- CALLBACK
list: IdName[];
page = -1;
limit = 10;
async ngOnInit() {
this.loadMore();
}
onClick(item: IdName) {
this.callback.click(item);
}
async onDel(item: IdName){
if(await this.callback.removeItem(item)) {
const i = this.list.findIndex(i=>i.id == item.id);
this.list.splice(i, 1);
}
}
async loadMore(){
this.page++;
this.list = await this.callback.getList(this.page, this.limit);
}
}
Komponen Induk
Sekarang kita dapat menggunakan komponen daftar di induk.
import { Component } from "@angular/core";
import { SuggestionService } from "./suggestion.service";
import { IdName, IListComponentCallback } from "./list.component";
type Suggestion = IdName;
@Component({
selector: "my-app",
template: `
<list-ctrl class="left" [callback]="this"></list-ctrl>
<div class="right" *ngIf="msg">{{ msg }}<br/><pre>{{item|json}}</pre></div>
`,
styles:[`
.left{ width: 50%; }
.left,.right{ color: blue; display: inline-block; vertical-align: top}
.right{max-width:50%;overflow-x:scroll;padding-left:1rem}
`]
})
export class ParentComponent implements IListComponentCallback<Suggestion> {
msg: string;
item: Suggestion;
constructor(private suggApi: SuggestionService) {}
getList(page: number, limit: number): Promise<Suggestion[]> {
return this.suggApi.getSuggestions(page, limit);
}
removeItem(item: Suggestion): Promise<boolean> {
return this.suggApi.removeSuggestion(item.id)
.then(() => {
this.showMessage('removed', item);
return true;
})
.catch(() => false);
}
click(item: Suggestion): void {
this.showMessage('clicked', item);
}
private showMessage(msg: string, item: Suggestion) {
this.item = item;
this.msg = 'last ' + msg;
}
}
Perhatikan bahwa <list-ctrl>
menerimathis
(komponen induk) sebagai objek panggilan balik. Satu keuntungan tambahan adalah tidak diperlukan untuk mengirimkan instance induk, itu bisa berupa layanan atau objek apa pun yang mengimplementasikan antarmuka jika use case Anda mengizinkannya.
Contoh lengkap ada di stackblitz ini .
@Input
cara yang disarankan membuat spagetti kode saya dan tidak mudah dipelihara ..@Output
s adalah cara yang jauh lebih alami untuk melakukan apa yang saya inginkan. Akibatnya saya mengubah jawaban yang diterima