在 *ngFor 的情况下,是什么为 ngTemplate 提供了上下文?
What gives the context to ngTemplate in case of *ngFor?
我对 ngTemplateOutletContext
有一些困惑,特别是它是如何传递给 ngTemplate
或谁将它传递给 ngTemplate
的,它围绕着应用了 *ngFor
的元素.当我将它与方式进行比较时,当我们显式传递 which ngTemplate
进行渲染时,混乱就会增加。
这是我认为当我们显式传递模板时会发生什么 -
假设我们有一个 ngContainer
/ ngTemplate
/ ( Literally any HTML element as ngTemplateOutlet & ngTemplateOutletContext can be applied to any element)
,现在我们选择显式提供我们之前创建的模板。像这样-
<ng-template #temp let-number>
<p>{{number}}</p>
</ng-template>
然后我们将它传递给我们应用了 ngTemplateOutlet
和 ngTemplateOutletContext
的某个元素,就像这样 -
<div [ngTemplateOutlet]="temp" [ngTemplateOutletContext]="{$implicit: 4}">
</div>
(我们应该使用ng-container
来进行上述操作,因为它不会在DOM中,但这里与我无关。)
现在 temp
ngTemplate
将具有上下文,就像 div
(或任何其他父容器)传递的内容一样 -
我在这里的理解是,我们消除了 ngTemplateOutlet
中提供的 ng-template
,并在 ngTemplateOutletContext
中传递了上下文。我们创建局部变量以在模板本身中使用。
问题
当我们使用 *ngFor
比如 -
<p *ngFor="let number of data">
{{number}}
</p>
它通过以下方式脱糖 -
<ng-template #temp ngFor [ngForOf]="data" let-number>
<p>{{number}}</p>
</ng-template>
其中 ts
文件中的 data
变量是 data = [1,2,3]
The question is
-
1.) 谁为这个脱糖 ng-template
提供值(上下文),以便它能够将 let-number 绑定到 $implicit 属性。我查看了 ngForOfContext ,在那里我发现提供了一些变量,这就是为什么我们能够像 even
、index
这样的绑定变量 -
<p *ngFor="let number of data; let i=index; let isEven=even">
但是谁在这种情况下向 ng-template
提供了这些变量。 (当我们显式传递模板时,父容器(div
这里)提供了我们之前看到的上下文)
2.) 当我们设置 ngForTemplate
时,它需要一个类型为 TemplateRef
的模板,如此处所示-
将 p
与 *ngFor 指令一起使用允许它,但是在使用 ngFor
的脱糖版本时明确设置 p
的引用不允许它,即 -
<ng-template #temp ngFor [ngForOf]="data" [ngForTemplate]="pTemplate" let-number>
其中 pTemplate
是 -
<p #pTemplate *ngFor="let number of data; let i=index; let isEven=even">
{{number}} {{i}} {{isEven}}
</p>
但它无法识别 ngForTemplate
中的 ptemplate
。如果它不能将 pTemplate
识别为有效的 ngForTemplate
,它如何能够在 *ngFor
版本中消除 p
?
PS:如果我在问题前对ng-template
的理解不正确,我也很乐意纠正。
当我们像这样使用 ngFor 指令时:
<ng-container *ngFor="let number of data;let i = index;let isEven=even">
<p [class.even]="isEven">{{i}} : {{number}}</p>
</ng-container>
内部html是一个ng-template。 ngFor 指令为循环的每次迭代提供此模板的上下文。
如您所述,在 ngFor 指令中有一个 ngForTemplate 输入。我们可以使用它来设置在 ngFor 内部 Html
之外声明的模板
<ng-template #pTemplate let-number let-isEven="even" let-i="index">
<p [class.even]="isEven">{{i}} : {{number}}</p>
</ng-template>
<ng-container *ngFor="let number of data;let i = index;let isEven=even;template: pTemplate">
</ng-container>
因此 ngFor 指令为该模板提供了上下文。此上下文的类型为 ngForOfContext
我们可以通过自己提供上下文来将此模板与 ngTemplateOutlet 一起使用:
<ng-container *ngTemplateOutlet="pTemplate;context:{$implicit:43,even:true,index:2}">
</ng-container>
但是 *ngFor 语法是 ngTemplate 的语法糖。我们可以像这样不加糖使用它:
<ng-template ngFor [ngForOf]="data" let-number let-isEven="even" let-i="index">
<p [class.even]="isEven">{{i}} : {{number}}</p>
</ng-template>
这里的ng-template依然是每次迭代应用的模板。我们还可以通过提供上下文在 ngTemplateOutlet 中使用它:
<ng-template #templ ngFor [ngForOf]="data" let-number let-isEven="even" let-i="index">
<p [class.even]="isEven">{{i}} : {{number}}</p>
</ng-template>
<ng-container *ngTemplateOutlet="templ;context:{$implicit:43,even:true,index:2}">
</ng-container>
但是如果在 ngForTemplate
输入中使用去糖语法,我们必须声明第二个 ng-template 元素。因为如果我们尝试在 ng-template 之外的任何其他对象上应用不带 * 的 ngFor 指令,我们会收到错误。
如果我们查看 source code of the ngFor directive 我们可以看到它的构造函数中需要一个 templateRef。但是这个模板 ref 的值也是由 ngForTemplate 输入设置的。
所以我们需要写
<ng-template #pTemplate let-number let-isEven="even" let-i="index">
<p [class.even]="isEven">{{i}} : {{number}}</p>
</ng-template>
<ng-template ngFor [ngForOf]="data" [ngForTemplate]="pTemplate"></ng-template>
<!-- And we cannot write : -->
<ng-container ngFor [ngForOf]="data" [ngForTemplate]="pTemplate"></ng-container>
在这种情况下,我们有 2 个模板,但只使用了一个,因此我们放置 ngFor 的模板不需要上下文,它的唯一目的是能够调用 ngFor 指令。
希望这能回答您的问题。
我对 ngTemplateOutletContext
有一些困惑,特别是它是如何传递给 ngTemplate
或谁将它传递给 ngTemplate
的,它围绕着应用了 *ngFor
的元素.当我将它与方式进行比较时,当我们显式传递 which ngTemplate
进行渲染时,混乱就会增加。
这是我认为当我们显式传递模板时会发生什么 -
假设我们有一个 ngContainer
/ ngTemplate
/ ( Literally any HTML element as ngTemplateOutlet & ngTemplateOutletContext can be applied to any element)
,现在我们选择显式提供我们之前创建的模板。像这样-
<ng-template #temp let-number>
<p>{{number}}</p>
</ng-template>
然后我们将它传递给我们应用了 ngTemplateOutlet
和 ngTemplateOutletContext
的某个元素,就像这样 -
<div [ngTemplateOutlet]="temp" [ngTemplateOutletContext]="{$implicit: 4}">
</div>
(我们应该使用ng-container
来进行上述操作,因为它不会在DOM中,但这里与我无关。)
现在 temp
ngTemplate
将具有上下文,就像 div
(或任何其他父容器)传递的内容一样 -
我在这里的理解是,我们消除了 ngTemplateOutlet
中提供的 ng-template
,并在 ngTemplateOutletContext
中传递了上下文。我们创建局部变量以在模板本身中使用。
问题
当我们使用 *ngFor
比如 -
<p *ngFor="let number of data">
{{number}}
</p>
它通过以下方式脱糖 -
<ng-template #temp ngFor [ngForOf]="data" let-number>
<p>{{number}}</p>
</ng-template>
其中 ts
文件中的 data
变量是 data = [1,2,3]
The question is
-
1.) 谁为这个脱糖 ng-template
提供值(上下文),以便它能够将 let-number 绑定到 $implicit 属性。我查看了 ngForOfContext ,在那里我发现提供了一些变量,这就是为什么我们能够像 even
、index
这样的绑定变量 -
<p *ngFor="let number of data; let i=index; let isEven=even">
但是谁在这种情况下向 ng-template
提供了这些变量。 (当我们显式传递模板时,父容器(div
这里)提供了我们之前看到的上下文)
2.) 当我们设置 ngForTemplate
时,它需要一个类型为 TemplateRef
的模板,如此处所示-
将 p
与 *ngFor 指令一起使用允许它,但是在使用 ngFor
的脱糖版本时明确设置 p
的引用不允许它,即 -
<ng-template #temp ngFor [ngForOf]="data" [ngForTemplate]="pTemplate" let-number>
其中 pTemplate
是 -
<p #pTemplate *ngFor="let number of data; let i=index; let isEven=even">
{{number}} {{i}} {{isEven}}
</p>
但它无法识别 ngForTemplate
中的 ptemplate
。如果它不能将 pTemplate
识别为有效的 ngForTemplate
,它如何能够在 *ngFor
版本中消除 p
?
PS:如果我在问题前对ng-template
的理解不正确,我也很乐意纠正。
当我们像这样使用 ngFor 指令时:
<ng-container *ngFor="let number of data;let i = index;let isEven=even">
<p [class.even]="isEven">{{i}} : {{number}}</p>
</ng-container>
内部html是一个ng-template。 ngFor 指令为循环的每次迭代提供此模板的上下文。
如您所述,在 ngFor 指令中有一个 ngForTemplate 输入。我们可以使用它来设置在 ngFor 内部 Html
之外声明的模板<ng-template #pTemplate let-number let-isEven="even" let-i="index">
<p [class.even]="isEven">{{i}} : {{number}}</p>
</ng-template>
<ng-container *ngFor="let number of data;let i = index;let isEven=even;template: pTemplate">
</ng-container>
因此 ngFor 指令为该模板提供了上下文。此上下文的类型为 ngForOfContext
我们可以通过自己提供上下文来将此模板与 ngTemplateOutlet 一起使用:
<ng-container *ngTemplateOutlet="pTemplate;context:{$implicit:43,even:true,index:2}">
</ng-container>
但是 *ngFor 语法是 ngTemplate 的语法糖。我们可以像这样不加糖使用它:
<ng-template ngFor [ngForOf]="data" let-number let-isEven="even" let-i="index">
<p [class.even]="isEven">{{i}} : {{number}}</p>
</ng-template>
这里的ng-template依然是每次迭代应用的模板。我们还可以通过提供上下文在 ngTemplateOutlet 中使用它:
<ng-template #templ ngFor [ngForOf]="data" let-number let-isEven="even" let-i="index">
<p [class.even]="isEven">{{i}} : {{number}}</p>
</ng-template>
<ng-container *ngTemplateOutlet="templ;context:{$implicit:43,even:true,index:2}">
</ng-container>
但是如果在 ngForTemplate
输入中使用去糖语法,我们必须声明第二个 ng-template 元素。因为如果我们尝试在 ng-template 之外的任何其他对象上应用不带 * 的 ngFor 指令,我们会收到错误。
如果我们查看 source code of the ngFor directive 我们可以看到它的构造函数中需要一个 templateRef。但是这个模板 ref 的值也是由 ngForTemplate 输入设置的。
所以我们需要写
<ng-template #pTemplate let-number let-isEven="even" let-i="index">
<p [class.even]="isEven">{{i}} : {{number}}</p>
</ng-template>
<ng-template ngFor [ngForOf]="data" [ngForTemplate]="pTemplate"></ng-template>
<!-- And we cannot write : -->
<ng-container ngFor [ngForOf]="data" [ngForTemplate]="pTemplate"></ng-container>
在这种情况下,我们有 2 个模板,但只使用了一个,因此我们放置 ngFor 的模板不需要上下文,它的唯一目的是能够调用 ngFor 指令。
希望这能回答您的问题。