更好的 *ngIf 链接和“0”值检测?
Better *ngIf chaining and `0` value detection?
我们构建了一个类似仪表板的界面,并经常收到带有可选字段的通用对象,例如下面的 event
对象。 event
可能在加载模板时未定义,它可能有也可能没有 daysRemaining ?: number
参数;如果设置了,可能是0
.
为了确保在上述场景中实际打印出 0
值,我们使用此模式:
<div *ngIf="event?.daysRemaining?.toString().length > 0">
{{event.daysRemaining}} days
</div>
(.toString()
是必需的,因为 属性 'length' 在类型 'number' 上不存在。)
我们的对象树可以比上面的例子多深。我们可以在 <ng-container>
的 *ngIf
中包含共同的父树,但我们很少这样做。
必须有更优雅的方法来做到这一点,特别是关于需要在几乎每个可选 number
.
上调用 .toString()
这似乎更有效率:
<div>
{{event?.daysRemaining + ' days'}}
</div>
但缺点是如果我们需要选择性地向 <div>
添加内容(例如 color: red
时 daysRemaining < 0
),我们仍然需要所有检查。
您可以使用方法检查组件中的条件。
<div *ngIf="daysRemaining(event)">
{{event.daysRemaining}} days
</div>
打字稿方法将如
daysRemaining(event){
if(event && event.daysRemaining.toString().length > 0){
return true;
} else {
return false;
}
}
在组件 class 中,我会使用类似的东西:
get daysRemaining(){
return this.event && (this.event.daysRemaining || this.event.daysRemaining === 0) ?
this.event.daysRemaining + ' days' : undefined;
}
并在模板中:
<div>
{{daysRemaining}}
</div>
如果您认为自己可能经常这样做,您可以创建一个管道:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'printIfDefined'})
export class PrintIfDefinedPipe implements PipeTransform {
transform(value:number, suffix?:string): number {
let suffix = (suffix ? ' ' + suffix : '');
return (value || value === 0) ? value + suffix : undefined;
}
}
并在模板中:
<div>
{{event?.daysRemaining | printIfDefined: 'days' }}
</div>
在这两种选择中,div 仍然在 de DOM 上注入,但由于它没有内容,因此不应影响您的应用程序(除非您具有固定宽度的 css 或类似的东西)。
如果 DOM space 占用困扰你,另一种选择可能是指令:
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[print-if-defined]'
})
export class PrintIfDefinedDirective {
constructor(private el: ElementRef) { }
@Input('suffix')
suffix:string;
@Input('value')
set value(nm:number) {
this.el.nativeElement.style.display = nm || nm === 0 ? "" : "none";
this.el.nativeElement.textContent = nm + (this.suffix ? ' ' + this.suffix : '');
}
}
并像
一样使用它
<div print-if-defined [value]="event?.daysRemaining" suffix="days"></div>
您可以在以下位置看到所有 运行:
https://plnkr.co/edit/gFeKJilYGdt5ttENjKUG?p=preview
我们构建了一个类似仪表板的界面,并经常收到带有可选字段的通用对象,例如下面的 event
对象。 event
可能在加载模板时未定义,它可能有也可能没有 daysRemaining ?: number
参数;如果设置了,可能是0
.
为了确保在上述场景中实际打印出 0
值,我们使用此模式:
<div *ngIf="event?.daysRemaining?.toString().length > 0">
{{event.daysRemaining}} days
</div>
(.toString()
是必需的,因为 属性 'length' 在类型 'number' 上不存在。)
我们的对象树可以比上面的例子多深。我们可以在 <ng-container>
的 *ngIf
中包含共同的父树,但我们很少这样做。
必须有更优雅的方法来做到这一点,特别是关于需要在几乎每个可选 number
.
.toString()
这似乎更有效率:
<div>
{{event?.daysRemaining + ' days'}}
</div>
但缺点是如果我们需要选择性地向 <div>
添加内容(例如 color: red
时 daysRemaining < 0
),我们仍然需要所有检查。
您可以使用方法检查组件中的条件。
<div *ngIf="daysRemaining(event)">
{{event.daysRemaining}} days
</div>
打字稿方法将如
daysRemaining(event){
if(event && event.daysRemaining.toString().length > 0){
return true;
} else {
return false;
}
}
在组件 class 中,我会使用类似的东西:
get daysRemaining(){
return this.event && (this.event.daysRemaining || this.event.daysRemaining === 0) ?
this.event.daysRemaining + ' days' : undefined;
}
并在模板中:
<div>
{{daysRemaining}}
</div>
如果您认为自己可能经常这样做,您可以创建一个管道:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'printIfDefined'})
export class PrintIfDefinedPipe implements PipeTransform {
transform(value:number, suffix?:string): number {
let suffix = (suffix ? ' ' + suffix : '');
return (value || value === 0) ? value + suffix : undefined;
}
}
并在模板中:
<div>
{{event?.daysRemaining | printIfDefined: 'days' }}
</div>
在这两种选择中,div 仍然在 de DOM 上注入,但由于它没有内容,因此不应影响您的应用程序(除非您具有固定宽度的 css 或类似的东西)。
如果 DOM space 占用困扰你,另一种选择可能是指令:
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[print-if-defined]'
})
export class PrintIfDefinedDirective {
constructor(private el: ElementRef) { }
@Input('suffix')
suffix:string;
@Input('value')
set value(nm:number) {
this.el.nativeElement.style.display = nm || nm === 0 ? "" : "none";
this.el.nativeElement.textContent = nm + (this.suffix ? ' ' + this.suffix : '');
}
}
并像
一样使用它<div print-if-defined [value]="event?.daysRemaining" suffix="days"></div>
您可以在以下位置看到所有 运行: https://plnkr.co/edit/gFeKJilYGdt5ttENjKUG?p=preview