Başka bir alternatif.
OP bir geri arama kullanmanın yolunu sordu. Bu durumda özellikle @serginho tarafından kabul edilen cevap olarak kabul edilecek bir olayı (örneğinde: bir tıklama olayını) işleyen bir işleve atıfta bulundu: @Output
ve ile EventEmitter
.
Bununla birlikte, geri arama ve olay arasında bir fark vardır: Geri arama ile alt bileşeniniz, üst öğeden bazı geri bildirimler veya bilgiler alabilir, ancak bir etkinlik yalnızca bir şeyin herhangi bir geri bildirim beklemeden olduğunu bildirebilir.
Geri bildirimin gerekli olduğu kullanım durumları vardır, ör. bir renk veya bileşenin işlemesi gereken öğelerin bir listesini edinin. Bazı yanıtların önerdiği gibi ilişkili işlevleri kullanabilirsiniz veya arabirimleri kullanabilirsiniz (bu her zaman benim tercihimdir).
Misal
Diyelim ki bu alanlara sahip tüm veritabanı tablolarınızla kullanmak istediğiniz {id, name} öğelerinin bir listesi üzerinde çalışan genel bir bileşene sahipsiniz. Bu bileşen:
- bir dizi öğeyi (sayfa) alma ve bunları bir listede gösterme
- bir öğenin kaldırılmasına izin ver
- bir öğenin tıklandığını bildirir, böylece üst öğe bazı işlemler yapabilir.
- öğelerin sonraki sayfasını almayı sağlar.
Alt Bileşen
Normal bağlanma kullanıldığında 1 @Input()
ve 3 @Output()
parametreye ihtiyacımız olurdu (ancak ana öğeden geri bildirim alınmadan). Ör. <list-ctrl [items]="list" (itemClicked)="click($event)" (itemRemoved)="removeItem($event)" (loadNextPage)="load($event)" ...>
, ancak bir arayüz oluşturmak için yalnızca bir taneye ihtiyacımız olacak @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);
}
}
Üst Bileşen
Artık üst öğedeki liste bileşenini kullanabiliriz.
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;
}
}
Not <list-ctrl>
alır this
geri nesnesi olarak (ana bileşen). Ek bir avantaj, üst örneği göndermenin gerekli olmamasıdır, kullanım durumunuz izin veriyorsa, bir hizmet veya arabirimi uygulayan herhangi bir nesne olabilir.
Bunun tam örneği bu stackblitz'de .
@Input
yol benim kod spagetti yapılan ve bakımı kolay değil ..@Output
s istediğim yapmak çok daha doğal bir yoludur. Sonuç olarak kabul edilen cevabı değiştirdim