49

我正在尝试找出如何在ngFor loop.

我有一个这样的循环:

<td *ngFor="#prod of products">
  <a href="{{getBuild(branch,prod)?.url}}">
    {{getBuild(branch,prod)?.status}}
   </a>
</td>

您可以看到getBuild呼叫必须重复多次。(在我的实际示例中更多次)。我想要一种方法来在循环中的模板中创建这个变量并简单地重用它。

有没有办法做到这一点?

4

7 回答 7

18

我认为局部变量(用#字符定义)不适用于您的用例。

事实上,当您在 HTML 元素上定义局部变量时,它对应于组件(如果有)。当元素上没有组件时,变量引用元素本身。

为局部变量指定值允许您选择与当前元素关联的特定指令。例如:

<input #name="ngForm" ngControl="name" [(ngModel)]="company.name"/>

将设置与变量ngForm中的当前关联的指令的实例。name

因此,局部变量不针对您想要的,即设置为循环的当前元素创建的值。

如果你尝试做这样的事情:

<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

有关详细信息,请参阅此链接:http: //victorsavkin.com/post/119943127151/angular-2-template-syntax,“局部变量”部分。

除了迭代的当前元素,只提供了一组导出值,ngFor可以别名为局部变量:indexlast和。evenodd

请参阅此链接:https ://angular.io/docs/ts/latest/api/common/NgFor-directive.html

您可以做的是创建一个子组件来显示循环中的元素。它将接受当前元素作为参数并创建您的“局部变量”作为组件的属性。然后,您将能够在组件的模板中使用此属性,以便循环中的每个元素创建一次。这是一个示例:

@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>
于 2016-02-07T20:15:10.890 回答
17

我认为这是制作子组件的经典案例。

<td *ngFor="#prod of products">
    <subComp [prod]=prod></subComp>
</td>

然后,您的组件将有一个prod输入并在OnInit.

简单的例子plunk here

于 2016-02-07T20:04:41.383 回答
13

使用角度 4,您可以执行以下操作:

<td *ngFor="#prod of products">
  <div *ngIf="getBuild(branch,prod); let build">
    <a href="{{build.url}}">
     {{build.status}}
    </a>
  </div>
</td>
于 2018-11-30T13:30:31.693 回答
4

尽管可以就简单地编写一个新的子组件的优点进行争论。我认为以下解决方案是对所提问题的最正确答案。

<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>

查看这个的代码框
这将允许定义多个模板变量,并无限次地重用计算的输出。

使用 ng-template 的原因:

  • 正如 OP 所提到的,这比一个全新的组件更轻。因此,如果您有一个重用计算逻辑的简单模板,这可能是一个不错的选择
  • 在某些情况下,模板需要在同一个文件中 - 例如,我使用“mat-stepper”(材料库)组件遇到了这个问题

避免使用 ng-template 的原因:

  • 如果代码应该在其他组件中可重用
  • 如果模板变得太复杂,它会变得更加混乱而不是有用
于 2021-06-24T09:42:35.920 回答
3

不,只需getBuild为每个branch/prod组合缓存结果,或者只要使用与以前相同的值调用它即可。

于 2016-02-07T19:55:39.793 回答
2

改进 *ngIf 解决方案,您可以始终拥有真实的条件,不留下任何罪魁祸首

<ng-container *ngFor="let item of items">
    <ng-container *ngIf="getMyVariableValue(item.id) || true; let myVariable">
        {{ content here }}
    </ng-container>
</ng-container>

我要注意的一个观察结果是,当函数“getMyVariableValue”返回nullundefined时,它并没有像我那样出现,而是它的值是true。我使用的是 Angular 11.2.3 版。

于 2021-06-09T13:47:26.087 回答
1

虽然不理想,但另一种方法可能是使用 *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 表达式返回一个对象,所以它总是 thruthy,所以 ng-container 中的内容总是会被渲染。结果对象被分配给状态变量,以后可以重用。ng-container 不插入 dom 元素。

于 2021-04-03T11:02:17.193 回答