这让我发疯:
这里是STACKBLITZ,它最能描述我的问题。
简而言之。我希望通过ChangeDetection(不包括ChangeDetection)检查CLOSED扩展面板NOT内的“东西”。
从cd-check-comp: Projected from Parent to Child
-视图中Parent
是STAMPED OUT,因此在每次检查parent
时都将对其进行检查。这是预期的行为,但是NOT DESIRED。
问题:
如何将投影的ng-template
(在此示例中为cdkPortal / TemplatePortal)放入与ViewContainer
相同的cd-check-comp: Im in Childs View
中?
如何更改/切换ViewContainerRef
的ng-template
。我想“执行/编码”Child
-Component内部的开关。
Stackblitz保存:
@Component({
selector: "parent",
template: `
<button (click)="tick()">Trigger app.tick()</button>
<mat-expansion-panel #ep1>
<mat-expansion-panel-header>
<mat-panel-title>
Stuff inside should only be checked if open
</mat-panel-title>
</mat-expansion-panel-header>
<child [disableCD]="!ep1.expanded">
<ng-template cdkPortal>
<cd-check-comp name='Projected from Parent to Child'></cd-check-comp>
</ng-template>
</child>
</mat-expansion-panel>
<cd-check-comp name='Im in parents View.'></cd-check-comp>
<p> Main Goal: <b>cd-check-comp: Projected from Parent to Child</b> should not be "checked" when the Panel is closed for the first time.</p>
`,
})
export class Parent {
tick() { setTimeout(() => {}); }
}
@Component({
selector: 'child',
template: `
<ng-template [cdkPortalOutlet]="_portal"></ng-template>
<cd-check-comp name="Im in Childs View"></cd-check-comp>
`,
})
export class Child implements OnInit {
@ContentChild(CdkPortal, {static: true}) _lazyPortal: CdkPortal;
@Input() disableCD: boolean;
_opened: BehaviorSubject<boolean>;
_portal: TemplatePortal;
constructor(
private _changeDetectorRef: ChangeDetectorRef, private _vcr: ViewContainerRef
) {
}
ngOnInit() {
this._opened = new BehaviorSubject(this.disableCD);
}
ngDoCheck() {
console.log('Child checked')
}
ngOnChanges(sc: SimpleChanges) {
// return;
this.disableCD ? this._changeDetectorRef.detach() : this._changeDetectorRef.reattach();
if (this._opened) { this._opened.next(this.disableCD); }
}
ngAfterContentInit() {
if (this._lazyPortal) {
this._opened.pipe(
startWith(null!),
filter(() => this._opened.value && !this._portal),
take(1)
).subscribe(() => {
this._portal = this._lazyPortal;
});
}
}
}
@Component({
selector: "cd-check-comp",
template: "<p>cd-check-comp: <b>{{name ? name : instanceCounter}}</b></p>",
styles: [':host { display: block; border: 1px dashed black}']
})
export class CdCheckComp implements DoCheck {
static counter = 0;
@Input() name: string;
instanceCounter: number;
constructor(private _vcr: ViewContainerRef) {
this.instanceCounter = ++CdCheckComp.counter;
}
ngDoCheck() {
console.log("checked:" + (this.name ? this.name : this.instanceCounter));
}
}
我认为您正在尝试分离错误的View
。
在ViewEngine中,如果在一个视图中声明了模板但将其插入到另一个视图中,则在检查其声明点时也会运行更改检测。
我将分离嵌入式插入的视图。为此,您可以通过ViewContainerRef
从插入视图的位置获取portal
。
child.html
<ng-template #portalContainer [cdkPortalOutlet]="_portal"></ng-template>
^^^^^^^^^^^^^^^^
add this
child.ts
export class Child implements OnInit {
@ViewChild('portalContainer', { read: ViewContainerRef, static: true })
portalContainer: ViewContainerRef;
ngOnChanges(sc: SimpleChanges) {
if (this.portalContainer.length) {
const view = this.portalContainer.get(0)!;
this.disableCD ? view.detach() : view.reattach();
}
...
}