Angular模板语法操作符及类型转换函数

管道操作符 ( | )

在进行数据绑定之前,表达式的结果可能需要一些转换。例如,可能希望把数字显示成金额、强制文本变成大写,或者过滤列表以及进行排序。

Angular 管道对像这样的小型转换来说是个明智的选择。 管道是一个简单的函数,它接受一个输入值,并返回转换结果。 它们很容易用于模板表达式中,只要使用管道操作符 (|) 就行了。

Angular 内置了一些管道,比如 DatePipeUpperCasePipeLowerCasePipeCurrencyPipePercentPipe。 它们全都可以直接用在任何模板中。

管道使用

<div>Title through uppercase pipe: {{title | uppercase}}</div>

管道操作符会把它左侧的表达式结果传给它右侧的管道函数。

还可以通过多个管道串联表达式:

<!-- Pipe chaining: convert title to uppercase, then to lowercase -->
<div>
  Title through a pipe chain:
  {{title | uppercase | lowercase}}
</div>

还能对它们使用参数:

<!-- pipe with configuration argument => "February 25, 1970" -->
<div>Birthdate: {{currentHero?.birthdate | date:'longDate'}}</div>

json 管道对调试绑定特别有用:

<div>{{currentHero | json}}</div>

它生成的输出是这样的:

{ "id": 0, "name": "Hercules", "emotion": "happy",
  "birthdate": "1970-02-25T08:00:00.000Z",
  "url": "http://www.imdb.com/title/tt0065832/",
  "rate": 325 }

自定义管道

import { Pipe, PipeTransform } from '@angular/core';
/*
 * Raise the value exponentially
 * Takes an exponent argument that defaults to 1.
 * Usage:
 *   value | exponentialStrength:exponent
 * Example:
 *   {{ 2 | exponentialStrength:10 }}
 *   formats to: 1024
*/
@Pipe({name: 'exponentialStrength'})
export class ExponentialStrengthPipe implements PipeTransform {
  transform(value: number, exponent: string): number {
    let exp = parseFloat(exponent);
    return Math.pow(value, isNaN(exp) ? 1 : exp);
  }
}

在这个管道的定义中体现了几个关键点:

  1. 管道是一个带有“管道元数据(pipe metadata)”装饰器的类。
  2. 这个管道类实现了 PipeTransform 接口的 transform 方法,该方法接受一个输入值和一些可选参数,并返回转换后的值。
  3. 当每个输入值被传给 transform 方法时,还会带上另一个参数,比如你这个管道就有一个 exponent(放大指数) 参数。
  4. 可以通过 @Pipe 装饰器来告诉 Angular:这是一个管道。该装饰器是从 Angular 的 core 库中引入的。
  5. 这个 @Pipe 装饰器允许你定义管道的名字,这个名字会被用在模板表达式中。它必须是一个有效的 JavaScript 标识符。 比如,你这个管道的名字是 exponentialStrength

使用时注意:

  • 你使用自定义管道的方式和内置管道完全相同。
  • 你必须在 AppModuledeclarations 数组中包含这个管道。

安全导航操作符 ( ?. ) 和空属性路径

Angular 的安全导航操作符 (?.) 是一种流畅而便利的方式,用来保护出现在属性路径中 nullundefined 值。 下例中,当 currentHero 为空时,保护视图渲染器,让它免于失败。

The current hero's name is {{currentHero?.name}}

如果下列数据绑定中 title 属性为空,会发生什么?

The title is {{title}}

这个视图仍然被渲染出来,但是显示的值是空;只能看到 “The title is”,它后面却没有任何东西。 这是合理的行为。至少应用没有崩溃。

假设模板表达式涉及属性路径,在下例中,显示一个空 (null) 英雄的 firstName

The null hero's name is {{nullHero.name}}

JavaScript 抛出了空引用错误,Angular 也是如此:

TypeError: Cannot read property 'name' of null in [null].

晕,整个视图都不见了。

如果确信 hero 属性永远不可能为空,可以声称这是合理的行为。 如果它必须不能为空,但它仍然是空值,实际上是制造了一个编程错误,它应该被捕获和修复。 这种情况应该抛出异常。

另一方面,属性路径中的空值可能会时常发生,特别是数据目前为空但最终会出现。

当等待数据的时候,视图渲染器不应该抱怨,而应该把这个空属性路径显示为空白,就像上面 title 属性那样。

不幸的是,当 currentHero 为空的时候,应用崩溃了。

可以通过用NgIf代码环绕它来解决这个问题。

<!--No hero, div not displayed, no error -->
<div *ngIf="nullHero">The null hero's name is {{nullHero.name}}</div>

或者可以尝试通过 && 来把属性路径的各部分串起来,让它在遇到第一个空值的时候,就返回空。

The null hero's name is {{nullHero && nullHero.name}}

这些方法都有价值,但是会显得笨重,特别是当这个属性路径非常长的时候。 想象一下在一个很长的属性路径(如 a.b.c.d)中对空值提供保护。

Angular 安全导航操作符 (?.) 是在属性路径中保护空值的更加流畅、便利的方式。 表达式会在它遇到第一个空值的时候跳出。 显示是空的,但应用正常工作,而没有发生错误。

<!-- No hero, no problem! -->
The null hero's name is {{nullHero?.name}}

在像 a?.b?.c?.d 这样的长属性路径中,它工作得很完美。

非空断言操作符(!)

在 TypeScript 2.0 中,你可以使用 --strictNullChecks 标志强制开启严格空值检查。TypeScript 就会确保不存在意料之外的 null 或 undefined。

在这种模式下,有类型的变量默认是不允许 null 或 undefined 值的,如果有未赋值的变量,或者试图把 null 或 undefined 赋值给不允许为空的变量,类型检查器就会抛出一个错误。

如果类型检查器在运行期间无法确定一个变量是 null 或 undefined,那么它也会抛出一个错误。 你自己可能知道它不会为空,但类型检查器不知道。 所以你要告诉类型检查器,它不会为空,这时就要用到非空断言操作符。

Angular 模板中的非空断言操作符(!)也是同样的用途。

例如,在用*ngIf来检查过 hero 是已定义的之后,就可以断言 hero 属性一定是已定义的*。

<!--No hero, no text -->
<div *ngIf="hero">
  The hero's name is {{hero!.name}}
</div>

在 Angular 编译器把你的模板转换成 TypeScript 代码时,这个操作符会防止 TypeScript 报告 "hero.name 可能为 nullundefined"的错误。

与安全导航操作符不同的是,非空断言操作符不会防止出现 null 或 undefined。 它只是告诉 TypeScript 的类型检查器对特定的属性表达式,不做 “严格空值检测”。

如果你打开了严格控制检测,那就要用到这个模板操作符,而其它情况下则是可选的。

类型转换函数 a n y ( any ( anyany( <表达式> ))

有时候,绑定表达式可能会报类型错误,并且它不能或很难指定类型。要消除这种报错,你可以使用 $any 转换函数来把表达式转换成 any 类型。

<!-- Accessing an undeclared member -->
<div>
  The hero's marker is {{$any(hero).marker}}
</div>

在这个例子中,当 Angular 编译器把模板转换成 TypeScript 代码时,$any 表达式可以防止 TypeScript 编译器报错说 marker 不是 Hero 接口的成员。

$any 转换函数可以和 this 联合使用,以便访问组件中未声明过的成员。

<!-- Accessing an undeclared member -->
<div>
  Undeclared members is {{$any(this).member}}
</div>

$any 转换函数可以在绑定表达式中任何可以进行方法调用的地方使用。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值