我如何更改ng-template的ViewContainerRef

问题描述 投票:0回答:1

这让我发疯:

  • 确保您检查堆栈闪电中的控制台

这里是STACKBLITZ,它最能描述我的问题。

简而言之。我希望通过ChangeDetection(不包括ChangeDetection)检查CLOSED扩展面板NOT内的“东西”。

cd-check-comp: Projected from Parent to Child-视图中

ParentSTAMPED OUT,因此在每次检查parent时都将对其进行检查。这是预期的行为,但是NOT DESIRED

问题:

如何将投影的ng-template(在此示例中为cdkPortal / TemplatePortal)放入与ViewContainer相同的cd-check-comp: Im in Childs View中?

如何更改/切换ViewContainerRefng-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));
  }
}
angular angular2-changedetection
1个回答
0
投票

我认为您正在尝试分离错误的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();
   }
   ...
 }

Forked Stackblitz

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.