Как я могу изменить ViewContainerRef для ng-шаблона - PullRequest
0 голосов
/ 07 февраля 2020

Это сводит меня с ума:

  • убедитесь, что вы проверяете консоль в стеке

Вот STACKBLITZ , который описывает мою проблему бест.

В двух словах. Я хочу, чтобы "Материал" внутри ЗАКРЫТО Панели расширения НЕ проверялся ChangeDetection (исключить из ChangeDetection).

cd-check-comp: Projected from Parent to Child равен STAMPED OUT из Parent -Просмотр, поэтому он проверяется при проверке parent. Это ожидаемое поведение, но НЕ ЖЕЛАЕТ .

Вопрос:

Как поставить проекцию ng-template (в этом примере cdkPortal / TemplatePortal) в те же ViewContainer, что и cd-check-comp: Im in Childs View?

Как изменить / переключить ViewContainerRef на ng-template. Я хотел бы «выполнить / кодировать» переключатель внутри Child -компонента.


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));
  }
}

1 Ответ

1 голос
/ 08 февраля 2020

Я думаю, что вы пытаетесь отсоединить неправильный 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();
   }
   ...
 }

Разветвленный стек-блиц

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...