Angular架構使開發人員能夠將資料從父組件傳遞到子組件。子組件由可在HTML範本中顯示或進一步處理以產生新的結果。 Angular在signal之前使用了@Input,但Angular 17引入了可以從父組件輸入signal inputs。
Signal input可以是必需的 (required),也可以是可選的 (optional)。 必需的signal input可以選擇傳入選項物件。可選signal input輸入初始值,也可以選擇傳入選項物件。
選項物件包含兩個屬性
alias - signal input的別名transform - 將輸入值轉換為最終值的函數import { Component, input } from '@angular/core';
@Component({
selector: 'app-star-war',
standalone: true,
template: `<p>Jedi Id: {{ jedi() }}</p>`,
})
export class StarWarComponent {
// required signal input
jedi = input.required<number>();
}
建立一個具有多個signal inputs的StarWarComponent。signal input與App組件綁定。 該組件具有HTML範本顯示必需的訊號輸入, jedi。
import { Component, VERSION } from '@angular/core';
import { StarWarComponent } from './star-war.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [StarWarComponent],
template: `
<app-star-war [jedi]="1" starShip="Star Destroyer" rgbTuple="yellow" />
<app-star-war [jedi]="10" />`,
})
export class App {}
App組件有兩個StarWarComponent。 第一個StarWarComponent的jedi輸入是1,第二個StarWarComponent的jedi輸入是10。
import { Component, input } from '@angular/core';
@Component({
selector: 'app-star-war',
standalone: true,
template: `
<p>Jedi Id: {{ jedi() }}</p>
<p>Sith Id: {{ sith() }}</p>
`,
})
export class StarWarComponent {
// required signal input
jedi = input.required<number>();
// optional signal input with a value
sith = input(4);
}
sith 是可選的signal input,初始值為4。當未向組件提供sith輸入值時,將使用初始值。
import { Component } from '@angular/core';
import { StarWarComponent } from './star-war.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [StarWarComponent],
template: `
<app-star-war [jedi]="1" />
<app-star-war [jedi]="10" [sith]="44" />
`,
})
export class App {}
第一個StarWarComponent 沒有輸入sith的值;因此,sith為 4。第二個StarWarComponent的 sith為 44。
import { NgStyle } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { ChangeDetectionStrategy, Component, computed, effect, inject, Injector, input, signal } from '@angular/core';
import { getPerson, Person } from './star-war.api';
import { StarWarPersonComponent } from './star-war-person.component';
import { RgbType, validateRGB } from './rgb';
import { toObservable, toSignal } from '@angular/core/rxjs-interop';
import { switchMap } from 'rxjs';
@Component({
selector: 'app-star-war',
standalone: true,
imports: [NgStyle, StarWarPersonComponent],
template: `
<h3>Star War Jedi vs Sith</h3>
<div [ngStyle]="backgrounStyle()">
<div style="display: flex; justify-content: space-between;">
<p>Jedi Id: {{ jedi() }}</p>
<p>Sith Id: {{ sith() }}</p>
<p>Star ship: {{ ship() }}</p>
</div>
<app-star-war-person [person]="fighter()" kind="Jedi Fighter" />
<app-star-war-person [person]="sithLord()" kind="Sith Lord" />
</div>
`,
})
export class StarWarComponent {
// required signal input
jedi = input.required<number>();
// optional signal input with a value
sith = input(4);
// signal input with alias
ship = input('Star Destroyer', { alias: 'starShip' })
// signal input with transform
rgbs = input.required({
alias: 'rgbTuple',
transform: (v: RgbType) => validateRGB(v)
});
}
ship signal input的別名是 starShip。 Signal 的初始值為"Star Destroyer"。rgbs signal input的別名是 rgbTuple。
import { Component } from '@angular/core';
import { StarWarComponent } from './star-war.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [StarWarComponent],
template: `
<app-star-war [jedi]="1" rgbTuple="yellow" />
<app-star-war [jedi]="10" [sith]="44" starShip="Jedi starfighter" [rgbTuple]="lightBlue" />`,
})
export class App {
lightBlue = [137, 207, 240] as [number, number, number];
}
在第二個 StarWarComponent 中,輸入名稱分別為 starShip 和 rgbTuple。
export type RgbType = [number, number, number] | string;
export function validateRGB(rgbValues: RgbType): string {
if (typeof rgbValues === 'string') {
return rgbValues;
}
const minRGB = 0;
const maxRGB = 255;
const [r, g, b] = rgbValues.map(value => Math.max(minRGB, Math.min(value, maxRGB)));
return `rgb(${r}, ${g}, ${b})`;
}
validateRGB 是一個接受字串或元組並傳回 RGB 值的函數。
import { Component, input } from '@angular/core';
import { RgbType, validateRGB } from './rgb';
@Component({
selector: 'app-star-war',
standalone: true,
template: '...',
})
export class StarWarComponent {
// signal input with transform
rgbs = input.required({
alias: 'rgbTuple',
transform: (v: RgbType) => validateRGB(v)
});
}
變換函數將輸入 (input) 轉換為 RGB 代碼 (RGB code)。
import { Component } from '@angular/core';
import { StarWarComponent } from './star-war.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [StarWarComponent],
template: `
<app-star-war [jedi]="1" rgbTuple="yellow" />
<app-star-war [jedi]="10" [sith]="44" starShip="Jedi starfighter" [rgbTuple]="lightBlue" />
`,
})
export class App {
lightBlue = [137, 207, 240] as [number, number, number];
}
lightBlue 值轉換為 rgb(137, 207, 240); 黃色並按原樣傳回。
我們可以根據 signal input 建立 computed signal。
import { NgStyle } from '@angular/common';
import { Component, computed, input } from '@angular/core';
import { RgbType, validateRGB } from './rgb';
@Component({
selector: 'app-star-war',
standalone: true,
imports: [NgStyle],
template: `<div [ngStyle]="backgrounStyle()"></div>`,
})
export class StarWarComponent {
// signal input with transform
rgbs = input.required({
alias: 'rgbTuple',
transform: (v: RgbType) => validateRGB(v)
});
// computed signal based on signal input
backgrounStyle = computed(() => ({
backgroundColor: this.rgbs()
}));
}
backgroundStyle 傳回背景顏色的 CSS 樣式。 CSS 樣式的背景顏色值等於rgbs signal input。然後,backgroundStyle signal的值被分配到NgStyle。
import { Component, inject, Injector, input, signal } from '@angular/core';
import { getPerson, Person } from './star-war.api';
import { toObservable, toSignal } from '@angular/core/rxjs-interop';
import { switchMap } from 'rxjs';
@Component({
selector: 'app-star-war',
standalone: true,
imports: [StarWarPersonComponent],
template: `
<p>Sith Id: {{ sith() }}</p>
<app-star-war-person [person]="sithLord()" kind="Sith Lord" />`,
})
export class StarWarComponent {
// optional signal input with a value
sith = input(4);
injector = inject(Injector);
sithLord = toSignal(toObservable(this.sith).pipe(switchMap((v) => getPerson(v, this.injector))));
}
類似地,StarWarComponent 也可以使用 toObservable 將signal input轉換為 Observable。 在範例中,該組件將 sith signal input轉換為 Observable,並將 id 傳送到函數以檢索星際大戰人物。最後,toSignal 函數會取得 Observable,建立一個signal,並將其指派給 sithLord。
@Component({
selector: 'app-star-war',
standalone: true,
imports: [StarWarPersonComponent],
template: `
<app-star-war-person [person]="sithLord()" kind="Sith Lord" />
`,
})
export class StarWarComponent {}
在範本中,sithLord 是 StarWarPersonComponent 的輸入 (input),用於顯示人物的詳細資料。
import {Component, input } from '@angular/core';
import { Person } from './star-war.api';
@Component({
selector: 'app-star-war-person',
standalone: true,
template: `
@let p = person();
@if(p) {
<p>Name: {{ p.name }}</p>
<p>Height: {{ p.height }}</p>
} @else {
<p>No info</p>
}
</div>`,
})
export class StarWarPersonComponent {
// required signal input
person = input<Person | undefined>(undefined);
}
StarWarPersonComponent 有一個必需的person signal input來顯示那個人的詳細資料。
類似地,effect可以追蹤signal input執行程式碼。 StarWarComponent在effect中使用jedi signal input,呼叫 Star War API來檢索人物,並設定fighter signal。訂閱 Observable 後,OnCleanUp 清理函數會在銷毀effect前取消subscription。
import { Component, effect, inject, Injector, input, signal } from '@angular/core';
import { getPerson, Person } from './star-war.api';
import { StarWarPersonComponent } from './star-war-person.component';
@Component({
selector: 'app-star-war',
standalone: true,
imports: [StarWarPersonComponent],
template: `
<p>Jedi Id: {{ jedi() }}</p>
<app-star-war-person [person]="fighter()" kind="Jedi Fighter" />`,
})
export class StarWarComponent {
// required signal input
jedi = input.required<number>();
injector = inject(Injector);
fighter = signal<Person | undefined>(undefined);
constructor() {
effect((OnCleanup) => {
const sub = getPerson(this.jedi(), this.injector)
.subscribe((result) => this.fighter.set(result));
OnCleanup(() => sub.unsubscribe());
});
}
}
在範本中,fighter是StarWarPersonComponent的輸入,用於顯示人物的詳細資料。
signal inputs是保存signal的輸入。signal inputs可以是必需的 (required) 或可選的 (optional)。signal inputs一個別名 (alias) 或一個變換函數 (transformation function來轉換輸入值。computed signal可以從signal input得出新值。toObservable 可以從signal input建立一個新的Observable。effect可以追蹤signal input執行程式碼。鐵人賽的第12天就這樣結束了。