如何在 ngFor 循环中创建变量?
How to create variable in ngFor loop?
我正在尝试了解如何在 ngFor loop
中创建变量。
我有一个这样的循环:
<td *ngFor="#prod of products">
<a href="{{getBuild(branch,prod)?.url}}">
{{getBuild(branch,prod)?.status}}
</a>
</td>
您可以看到 getBuild
调用必须重复多次。 (在我的实际示例中多次)。我想要一种在循环内在模板中创建此变量并简单地重用它的方法。
有办法吗?
不,只需将每个 branch
/prod
组合的结果缓存在 getBuild
中,或者只要使用与以前相同的值调用它。
我认为这是制作子组件的经典案例。
<td *ngFor="#prod of products">
<subComp [prod]=prod></subComp>
</td>
您的组件将有一个 prod
输入和 运行 在 OnInit
中一次所需的函数。
简单示例 plunk here
我认为局部变量(用 #
字符定义)不适用于您的用例。
事实上,当您在 HTML 元素上定义局部变量时,它对应于组件(如果有的话)。当元素上没有组件时,变量指的是元素本身。
为局部变量指定值允许您select 与当前元素关联的特定指令。例如:
<input #name="ngForm" ngControl="name" [(ngModel)]="company.name"/>
将在 name
变量中设置与当前关联的 ngForm
指令的实例。
所以局部变量不会以您想要的为目标,即设置为循环的当前元素创建的值。
如果您尝试这样做:
<div *ngFor="#elt of eltList" >
<span #localVariable="elt.title"></span>
{{localVariable}}
</div>
您将遇到以下错误:
Error: Template parse errors:
There is no directive with "exportAs" set to "elt.title" ("
<div *ngFor="#elt of eltList" >
<span [ERROR ->]#localVariable="elt.title"></span>
{{localVariable}}
</div>
"): AppComponent@2:10
Angular2 实际上在此处查找与提供的名称 elt.title
匹配的指令)...请参阅此 plunkr 以重现错误:https://plnkr.co/edit/qcMGr9FS7yQD8LbX18uY?p=preview
请参阅此 link:http://victorsavkin.com/post/119943127151/angular-2-template-syntax,第 "Local variables" 部分了解更多详细信息。
除了迭代的当前元素,ngFor
只提供了一组可以别名为局部变量的导出值:index
、last
、even
和 odd
.
看到这个link:https://angular.io/docs/ts/latest/api/common/NgFor-directive.html
您可以做的是创建一个子组件来显示循环中的元素。它将接受当前元素作为参数并创建 "local variable" 作为组件的属性。然后您将能够在组件的模板中使用此属性,以便在循环中为每个元素创建一次。这是一个示例:
@Component({
selector: 'elt',
template: `
<div>{{attr}}</div>
`
})
export class ElementComponent {
@Input() element;
constructor() {
// Your old "localVariable"
this.attr = createAttribute(element.title);
}
createAttribute(_title:string) {
// Do some processing
return somethingFromTitle;
}
}
以及使用方法:
<div *ngFor="#elt of eltList" >
<elt [element]="elt></elt>
</div>
使用 angular 4 你可以这样做:
<td *ngFor="#prod of products">
<div *ngIf="getBuild(branch,prod); let build">
<a href="{{build.url}}">
{{build.status}}
</a>
</div>
</td>
虽然不理想,但另一种方法可以使用 *ngIf
<td *ngFor="#prod of products">
<ng-container *ngIf="{build:getBuild(branch,prod)}; let state">
<a href="{{state.build?.url}}">
{{state.build?.status}}
</a>
</ng-container>
</td>
因为 *ngIf 表达式 returns 是一个对象,所以它将始终是真实的,因此 ng-container 中的内容将始终被渲染。结果对象被分配给状态变量,以后可以重用。 ng-container 不插入 dom 元素。
改进 *ngIf 解决方案,您可以始终拥有 true 条件而不会留下罪魁祸首
<ng-container *ngFor="let item of items">
<ng-container *ngIf="getMyVariableValue(item.id) || true; let myVariable">
{{ content here }}
</ng-container>
</ng-container>
我想指出的一个观察结果是,当函数“getMyVariableValue”返回 null 或 undefined 时,它并没有像 for我,相反,它的价值是 true。我使用的是 Angular 版本 11.2.3。
尽管可以就简单地编写一个新的子组件的优点进行争论。我认为以下解决方案是对所提问题的最正确答案。
<div *ngFor="let person of listOfPeople">
<ng-container
*ngTemplateOutlet="introText; context: { title: getTitle(person), color: person.color }"
></ng-container>
</div>
<ng-template #introText let-title="title" let-color="color">
<p [style.color]="color">
{{title}} loves the color {{color}}
</p>
</ng-template>
查看 codesandbox of this.
这将允许定义多个模板变量,并无限次地重复使用计算的输出。
使用ng-template的原因:
- 正如 OP 所提到的,这比一个全新的组件更轻。因此,如果您有一个重用计算逻辑的 简单 模板,这可能是一个不错的选择
- 在
在某些情况下,模板需要在同一个文件中 - 我 运行 进入
这带有一个 'mat-stepper'(Material 库)组件,例如
避免使用 ng-template 的原因:
- 如果代码应该在其他组件中重用
- 如果模板变得太复杂,它会变得更加混乱而不是有用
如果您不介意稍微修改一下,您还可以遍历 single-item 列表:
<td *ngFor="#prod of products">
<a *ngFor="let build of [getBuild(branch,prod)]" href="{{build?.url}}">
{{build?.status}}
</a>
</td>
我正在尝试了解如何在 ngFor loop
中创建变量。
我有一个这样的循环:
<td *ngFor="#prod of products">
<a href="{{getBuild(branch,prod)?.url}}">
{{getBuild(branch,prod)?.status}}
</a>
</td>
您可以看到 getBuild
调用必须重复多次。 (在我的实际示例中多次)。我想要一种在循环内在模板中创建此变量并简单地重用它的方法。
有办法吗?
不,只需将每个 branch
/prod
组合的结果缓存在 getBuild
中,或者只要使用与以前相同的值调用它。
我认为这是制作子组件的经典案例。
<td *ngFor="#prod of products">
<subComp [prod]=prod></subComp>
</td>
您的组件将有一个 prod
输入和 运行 在 OnInit
中一次所需的函数。
简单示例 plunk here
我认为局部变量(用 #
字符定义)不适用于您的用例。
事实上,当您在 HTML 元素上定义局部变量时,它对应于组件(如果有的话)。当元素上没有组件时,变量指的是元素本身。
为局部变量指定值允许您select 与当前元素关联的特定指令。例如:
<input #name="ngForm" ngControl="name" [(ngModel)]="company.name"/>
将在 name
变量中设置与当前关联的 ngForm
指令的实例。
所以局部变量不会以您想要的为目标,即设置为循环的当前元素创建的值。
如果您尝试这样做:
<div *ngFor="#elt of eltList" >
<span #localVariable="elt.title"></span>
{{localVariable}}
</div>
您将遇到以下错误:
Error: Template parse errors:
There is no directive with "exportAs" set to "elt.title" ("
<div *ngFor="#elt of eltList" >
<span [ERROR ->]#localVariable="elt.title"></span>
{{localVariable}}
</div>
"): AppComponent@2:10
Angular2 实际上在此处查找与提供的名称 elt.title
匹配的指令)...请参阅此 plunkr 以重现错误:https://plnkr.co/edit/qcMGr9FS7yQD8LbX18uY?p=preview
请参阅此 link:http://victorsavkin.com/post/119943127151/angular-2-template-syntax,第 "Local variables" 部分了解更多详细信息。
除了迭代的当前元素,ngFor
只提供了一组可以别名为局部变量的导出值:index
、last
、even
和 odd
.
看到这个link:https://angular.io/docs/ts/latest/api/common/NgFor-directive.html
您可以做的是创建一个子组件来显示循环中的元素。它将接受当前元素作为参数并创建 "local variable" 作为组件的属性。然后您将能够在组件的模板中使用此属性,以便在循环中为每个元素创建一次。这是一个示例:
@Component({
selector: 'elt',
template: `
<div>{{attr}}</div>
`
})
export class ElementComponent {
@Input() element;
constructor() {
// Your old "localVariable"
this.attr = createAttribute(element.title);
}
createAttribute(_title:string) {
// Do some processing
return somethingFromTitle;
}
}
以及使用方法:
<div *ngFor="#elt of eltList" >
<elt [element]="elt></elt>
</div>
使用 angular 4 你可以这样做:
<td *ngFor="#prod of products">
<div *ngIf="getBuild(branch,prod); let build">
<a href="{{build.url}}">
{{build.status}}
</a>
</div>
</td>
虽然不理想,但另一种方法可以使用 *ngIf
<td *ngFor="#prod of products">
<ng-container *ngIf="{build:getBuild(branch,prod)}; let state">
<a href="{{state.build?.url}}">
{{state.build?.status}}
</a>
</ng-container>
</td>
因为 *ngIf 表达式 returns 是一个对象,所以它将始终是真实的,因此 ng-container 中的内容将始终被渲染。结果对象被分配给状态变量,以后可以重用。 ng-container 不插入 dom 元素。
改进 *ngIf 解决方案,您可以始终拥有 true 条件而不会留下罪魁祸首
<ng-container *ngFor="let item of items">
<ng-container *ngIf="getMyVariableValue(item.id) || true; let myVariable">
{{ content here }}
</ng-container>
</ng-container>
我想指出的一个观察结果是,当函数“getMyVariableValue”返回 null 或 undefined 时,它并没有像 for我,相反,它的价值是 true。我使用的是 Angular 版本 11.2.3。
尽管可以就简单地编写一个新的子组件的优点进行争论。我认为以下解决方案是对所提问题的最正确答案。
<div *ngFor="let person of listOfPeople">
<ng-container
*ngTemplateOutlet="introText; context: { title: getTitle(person), color: person.color }"
></ng-container>
</div>
<ng-template #introText let-title="title" let-color="color">
<p [style.color]="color">
{{title}} loves the color {{color}}
</p>
</ng-template>
查看 codesandbox of this.
这将允许定义多个模板变量,并无限次地重复使用计算的输出。
使用ng-template的原因:
- 正如 OP 所提到的,这比一个全新的组件更轻。因此,如果您有一个重用计算逻辑的 简单 模板,这可能是一个不错的选择
- 在 在某些情况下,模板需要在同一个文件中 - 我 运行 进入 这带有一个 'mat-stepper'(Material 库)组件,例如
避免使用 ng-template 的原因:
- 如果代码应该在其他组件中重用
- 如果模板变得太复杂,它会变得更加混乱而不是有用
如果您不介意稍微修改一下,您还可以遍历 single-item 列表:
<td *ngFor="#prod of products">
<a *ngFor="let build of [getBuild(branch,prod)]" href="{{build?.url}}">
{{build?.status}}
</a>
</td>