谁拥有 angular dart 中的 TemplateRef 刷新周期?
Who owns the TemplateRef refreshing cycle in angular dart?
与 ngTemplateOutlet 一起使用时,TemplateRef 刷新周期出现问题。
考虑 HTML:
<card [value]="item" full>
<template #buttons let-obj="obj"> <!-- THE TEMPLATE -->
<button (click)="myBoolean = false"
*ngIf="myBoolean"> <!-- THIS IF -->
SET FALSE
</button>
<button (click)="myBoolean = true"
*ngIf="!myBoolean"> <!-- THIS IF -->
SET TRUE
</button>
</template>
</card>
<button (click)="myBoolean = !myBoolean">TOGGLE</button>
所以页面组件有一张卡片。
该卡具有此 属性:
@ContentChild('buttons')
TemplateRef buttons;
此代码使用 TemplateRef 按钮:
<template [ngTemplateOutlet]="buttons"
[ngTemplateOutletContext]="{ 'obj': value }"></template>
效果不错,按钮是根据页面组件的myBoolean变量显示的。此外,当您单击 <template>
中的按钮时,循环会起作用,并且它们会根据 myBoolean 变量进行更改。
问题是当 myBoolean 变量被 <template>
之外的东西改变时。在上面的 HTML 示例中,当我单击 TOGGLE 按钮时,myBoolean 变量发生变化,但是 <template>
不会相应地刷新。
那么,谁拥有 TemplateRef 的刷新?
我该怎么做才能让它正确刷新?
实例化 TemplateRef
的视图拥有所有权。因为您的组件使用 ChangeDetectionStrategy.OnPush
,它们的视图只会在
时更新
- 绑定在
组件的视图被触发,
- 输入值(例如
<card [input]="value">
)改变,或者
- 组件已注入
ChangeDetectorRef
并调用 changeDetector.markForCheck()
。
请注意,所有这三个条件都会导致视图被标记为检查;前两个是隐式的,最后一个是显式的。
在您的示例中,您将 <template>
投影到 <card>
组件的视图中。据推测,您的 <card>
组件然后通过 NgTemplateOutlet
在其自己的视图中呈现 <template>
。因此,为了在 myBoolean
更改时更新呈现的 <template>
,必须将 <card>
组件标记为检查。
单击 <template>
中的按钮时视图正确更新的原因是上述 (1)。事件处理程序将其呈现的视图(<card>
)标记为要检查。
同理不起作用当你点击父视图中的TOGGLE按钮时:它只标记要检查的父视图。因此,当由于标记为检查而检测到父视图更改时,将跳过 <card>
视图,因为 <card>
视图满足三个条件中的 none。
因此,为了在单击 TOGGLE 按钮时更新呈现的 <template>
,您需要处理程序以某种方式在 ChangeDetectorRef
上调用 markForCheck()
呈现 <template>
的视图。
好消息是这是可能的,但不幸的是它不是很干净。有多种方法可以实现此目的,但这里有一个想法:
在<card>
中添加一个方法来抽象使用ChangeDetectorRef
的细节:
@Component(...)
class CardComponent {
CardComponent(this._changeDetector);
final ChangeDetectorRef _changeDetector;
void updateButtons() {
_changeDetector.markForCheck();
}
}
在页面组件中查询 <card>
,并在按下切换时调用更新方法:
@Component(...)
class PageComponent {
@ViewChild(CardComponent)
CardComponent card;
void toggle() {
myBoolean = !myBoolean;
card.updateButtons();
}
}
<button (click)="toggle">TOGGLE</button>
希望这对您有所帮助,干杯!
与 ngTemplateOutlet 一起使用时,TemplateRef 刷新周期出现问题。
考虑 HTML:
<card [value]="item" full>
<template #buttons let-obj="obj"> <!-- THE TEMPLATE -->
<button (click)="myBoolean = false"
*ngIf="myBoolean"> <!-- THIS IF -->
SET FALSE
</button>
<button (click)="myBoolean = true"
*ngIf="!myBoolean"> <!-- THIS IF -->
SET TRUE
</button>
</template>
</card>
<button (click)="myBoolean = !myBoolean">TOGGLE</button>
所以页面组件有一张卡片。 该卡具有此 属性:
@ContentChild('buttons')
TemplateRef buttons;
此代码使用 TemplateRef 按钮:
<template [ngTemplateOutlet]="buttons"
[ngTemplateOutletContext]="{ 'obj': value }"></template>
效果不错,按钮是根据页面组件的myBoolean变量显示的。此外,当您单击 <template>
中的按钮时,循环会起作用,并且它们会根据 myBoolean 变量进行更改。
问题是当 myBoolean 变量被 <template>
之外的东西改变时。在上面的 HTML 示例中,当我单击 TOGGLE 按钮时,myBoolean 变量发生变化,但是 <template>
不会相应地刷新。
那么,谁拥有 TemplateRef 的刷新?
我该怎么做才能让它正确刷新?
实例化 TemplateRef
的视图拥有所有权。因为您的组件使用 ChangeDetectionStrategy.OnPush
,它们的视图只会在
- 绑定在 组件的视图被触发,
- 输入值(例如
<card [input]="value">
)改变,或者 - 组件已注入
ChangeDetectorRef
并调用changeDetector.markForCheck()
。
请注意,所有这三个条件都会导致视图被标记为检查;前两个是隐式的,最后一个是显式的。
在您的示例中,您将 <template>
投影到 <card>
组件的视图中。据推测,您的 <card>
组件然后通过 NgTemplateOutlet
在其自己的视图中呈现 <template>
。因此,为了在 myBoolean
更改时更新呈现的 <template>
,必须将 <card>
组件标记为检查。
单击 <template>
中的按钮时视图正确更新的原因是上述 (1)。事件处理程序将其呈现的视图(<card>
)标记为要检查。
同理不起作用当你点击父视图中的TOGGLE按钮时:它只标记要检查的父视图。因此,当由于标记为检查而检测到父视图更改时,将跳过 <card>
视图,因为 <card>
视图满足三个条件中的 none。
因此,为了在单击 TOGGLE 按钮时更新呈现的 <template>
,您需要处理程序以某种方式在 ChangeDetectorRef
上调用 markForCheck()
呈现 <template>
的视图。
好消息是这是可能的,但不幸的是它不是很干净。有多种方法可以实现此目的,但这里有一个想法:
在<card>
中添加一个方法来抽象使用ChangeDetectorRef
的细节:
@Component(...)
class CardComponent {
CardComponent(this._changeDetector);
final ChangeDetectorRef _changeDetector;
void updateButtons() {
_changeDetector.markForCheck();
}
}
在页面组件中查询 <card>
,并在按下切换时调用更新方法:
@Component(...)
class PageComponent {
@ViewChild(CardComponent)
CardComponent card;
void toggle() {
myBoolean = !myBoolean;
card.updateButtons();
}
}
<button (click)="toggle">TOGGLE</button>
希望这对您有所帮助,干杯!