ทางเลือกอื่น
OP ขอวิธีการใช้โทรกลับ ในกรณีนี้เขาหมายเฉพาะเพื่อฟังก์ชั่นที่ประมวลผลเหตุการณ์ (ในตัวอย่างของเขาเหตุการณ์คลิก) ซึ่งจะต้องได้รับการปฏิบัติเป็นคำตอบที่ได้รับการยอมรับจาก @serginho แนะนำ: ด้วยและ@Output
EventEmitter
อย่างไรก็ตามมีความแตกต่างระหว่างการโทรกลับและเหตุการณ์: ด้วยการโทรกลับองค์ประกอบลูกของคุณสามารถดึงความคิดเห็นหรือข้อมูลบางอย่างจากผู้ปกครอง แต่เหตุการณ์เพียงสามารถแจ้งให้ทราบว่าสิ่งที่เกิดขึ้นโดยไม่คาดหวังความคิดเห็นใด ๆ
มีหลายกรณีที่จำเป็นต้องใช้ข้อเสนอแนะเช่น รับสีหรือรายการองค์ประกอบที่องค์ประกอบต้องการจัดการ คุณสามารถใช้ฟังก์ชั่นที่ถูกผูกไว้ตามคำตอบที่แนะนำหรือคุณสามารถใช้อินเทอร์เฟซ
ตัวอย่าง
สมมติว่าคุณมีองค์ประกอบทั่วไปที่ทำงานกับรายการองค์ประกอบ {id, name} ที่คุณต้องการใช้กับตารางฐานข้อมูลทั้งหมดที่มีฟิลด์เหล่านี้ ส่วนประกอบนี้ควร:
- ดึงช่วงขององค์ประกอบ (หน้า) และแสดงในรายการ
- อนุญาตให้ลบองค์ประกอบ
- แจ้งว่าองค์ประกอบถูกคลิกเพื่อให้ผู้ปกครองสามารถดำเนินการบางอย่าง
- อนุญาตให้เรียกหน้าถัดไปขององค์ประกอบ
องค์ประกอบลูก
การใช้การเชื่อมปกติเราต้องใช้พารามิเตอร์1 @Input()
และ 3 @Output()
(แต่ไม่มีข้อเสนอแนะใด ๆ จากผู้ปกครอง) อดีต <list-ctrl [items]="list" (itemClicked)="click($event)" (itemRemoved)="removeItem($event)" (loadNextPage)="load($event)" ...>
แต่การสร้างอินเทอร์เฟซเราจะต้องการเพียงหนึ่ง@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);
}
}
ส่วนประกอบหลัก
ตอนนี้เราสามารถใช้องค์ประกอบรายการในแม่
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;
}
}
โปรดทราบว่า<list-ctrl>
ได้รับthis
(องค์ประกอบหลัก) เป็นวัตถุโทรกลับ ข้อดีอีกข้อหนึ่งคือไม่จำเป็นต้องส่งอินสแตนซ์หลักอาจเป็นบริการหรือวัตถุใด ๆ ที่ใช้อินเทอร์เฟซหากกรณีการใช้งานของคุณอนุญาต
ตัวอย่างที่สมบูรณ์อยู่ในstackblitzนี้
@Input
วิธีการอ่านในอนาคตที่แนะนำทำให้รหัสของฉัน spagetti และไม่ง่ายต่อการรักษา ..@Output
s เป็นวิธีที่เป็นธรรมชาติมากขึ้นในการทำสิ่งที่ฉันต้องการ เป็นผลให้ฉันเปลี่ยนคำตอบที่ยอมรับ