0%

angular-component-input

今天这篇我们讲解一下Angular中的Input,Input是Angular中的一个装饰器,它用来接收父组件传递过来的数据。

传统的@Input()写法

为了方便展示,我们定义两个组件, 一个父组件:ListComponent, 一个子组件:ListItemComponent。为了便于展示,我们将template和style都写在component.ts中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// list-item.component.ts
import {Component, Input} from '@angular/core';

@Component({
selector: 'app-list-item',
imports: [],
template: `
<div class="list-item">
<div>id: {{id}}</div>
<div>name: {{name}}</div>
</div>
`,
styles: [`
.list-item {
border: 1px solid #ccc;
margin-bottom: 10px;
padding: 10px;
}
`]
})
export class ListItemComponent {
@Input({required: true}) id: string = '';
@Input() name: string = '';
}

ListItemComponent中,我们定义了两个属性:idname,并且使用了@Input装饰器。@Input装饰器有一个可选的参数required,如果设置为true,则表示这个属性是必须的,如果使用组件时没有给该字段赋值,则会报错。

接下来我们在ListComponent中使用ListItemComponent组件,并传递数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// list.component.ts
import { Component } from '@angular/core';
import {ListItemComponent} from '../list-item/list-item.component';

@Component({
selector: 'app-list',
imports: [ListItemComponent],
template: `
<div class="list">
@for (item of listItems; track item.id) {
<app-list-item [id]="item.id" [name]="item.name"/>
}
</div>
`,
styleUrl: './list.component.scss'
})
export class ListComponent {
listItems = [
{id: '1', name: 'item 1'},
{id: '2', name: 'item 2'},
]
}

@Input定义的字段,需要通过property binding的方式传递数据,即[id]="item.id"[name]="item.name"

基于signal的input写法

以上是旧版的写法,从Angular 17.1开始,我们可以使用新版的基于signal的input语法了。

1
2
3
4
5
6
7
8
9
import {Component, input} from '@angular/core'; // import 'input'

export class ListItemComponent {
// @Input({required: true}) id: string = '';
// @Input() name: string = '';

id = input.required<string>();
name = input<string>('');
}

由于这种类型的input的值对应的是一个signal, 所以读取值的时候,要加(),id -> id(), name -> name()

1
2
3
4
5
6
template: `
<div class="list-item">
<div>id: {{id()}}</div>
<div>name: {{name()}}</div>
</div>
`

default value

1
value = input(0); // 0 is default value

specify type

Note that, for simple values, typescript can infer the type by value, but for complex types, you need to specify the type.

1
2
value = input<number>(0); // value = input(0); // totally ok
value = input<string>(''); // value = input(''); // totally ok

required

1
value = input.required<number>(); // required

Input transform

1
2
3
4
5
6
7
8
9
export class ListItemComponent {
id = input.required<string>();
name = input('', {transform: trimString}); // apply transform
}

// define transform function, transform function should be statically analyzable and pure function.
function trimString(value: string | undefined): string {
return value?.trim() ?? '';
}

Built-in transform

  1. booleanAttribute - imitates the behavior of standard HTML boolean attributes, where the presence of the attribute indicates a “true” value. However, Angular’s booleanAttribute treats the literal string “false” as the boolean false.
  2. numberAttribute - attempts to parse the given value to a number, producing NaN if parsing fails.

Input alias

1
value = input(0, {alias: 'sliderValue'}); // aliasValue is the alias name

在模板中使用sliderValue, 注意,组件代码中仍然只能使用value

1
<custom-slider [sliderValue]="50" />

References

  1. https://angular.dev/guide/components/inputs