Angular 4 中如何从 Controller 访问已排序的管道数组(使用 *ngFor 和管道生成)

How to Access Sorted Pipe Array (generated with *ngFor and pipes) from Controller in Angular 4

如何访问在控制器内的 *ngFor 中声明的变量?

我有这样的代码:

<song *ngFor="let track of music | async | sortMusic: [sortBy] as sortedTracks" [trackInfo]="track" (click)="toggleTrack(track)"></song>

我想访问 "sortedTracks" 变量。我有兴趣从具有上述代码的组件访问它,而不是从歌曲组件控制器访问它。

更新

确实应该很容易:

@ViewChild(NgForOf) ngForDir: NgForOf<any>;

this.ngForDir.ngForOf

Example

旧版本

1) 特别指示

我们可以编写帮助我获得它的指令:

ngfor-as.directive.ts

import { Directive, EmbeddedViewRef, NgIterable, ViewContainerRef } from '@angular/core';
import { NgForOfContext } from '@angular/common';

@Directive({
    selector: '[ngForOf]'
})
export class NgForOfAsDirective<T> {
    constructor(private vcRef: ViewContainerRef) {}

    public get asValue(): NgIterable<T> {
      const viewRef = this.vcRef.get(0) as EmbeddedViewRef<NgForOfContext<T>>;
      return viewRef ? viewRef.context.ngForOf : null;
    }
}

一旦我们在上面创建了指令,我们就可以使用 @ViewChild 来获取该指令的实例:

@Component({
  selector: 'my-app',
  template: `
    <song *ngFor="let track of music | async | sortMusic: sortBy as sortedTracks" ...></song>
  `
})
export class AppComponent {
  ...

  @ViewChild(NgForOfAsDirective) ngForAs: NgForOfAsDirective<any[]>;

  ngAfterViewInit() {
    console.log(this.ngForAs.asValue);
  }
}

Stackblitz Example

2) 直接从 ViewContainerRef 获取值

如果您不想创建一个指令,您可以只获取 ngForOf 指令使用的 ViewContainer

@Component({
  selector: 'my-app',
  template: `
    <song *ngFor="let track of music | async | sortMusic: sortBy as sortedTracks" ...></song>
  `
})
export class AppComponent {

  @ViewChild(TemplateRef, { read: ViewContainerRef }) vcRef: ViewContainerRef;

  get asMusicValue(): NgIterable<any> {
    const viewRef = this.vcRef.get(0) as EmbeddedViewRef<NgForOfContext<any>>;
    return viewRef ? viewRef.context.ngForOf : null;
  }

  ...

  ngAfterViewInit() {
    console.log(this.asMusicValue);
  }
}

Stackblitz example


当然,如果您的模板中有多个 ngForOf 指令,那么您在查询 ViewContainerRef 时应该更加精确。

为此,您可以使用以下选项之一:

  • @ViewChildren 如果知道确切的顺序 (example)

@ViewChildren(TemplateRef, { read: ViewContainerRef }) vcRefs: QueryList<ViewContainerRef>;
...
this.vcRefs.first.get(0)
            ^^^^^
  • ngForOf (example) 的扩展形式:

<ng-template #someId 
   let-track 
   ngFor 
   [ngForOf]="music | async | sortMusic: sortBy" 
   let-sortedTracks="ngFor">
  <song [trackInfo]="track"></song>
</ng-template>
  • 带有特殊选择器的指令(example

@Directive({
  selector: '[ngForOf=music | async | sortMusic: sortBy ]'
})
export class NgForOfMusic {}

...
@ViewChild(NgForOfMusic, { read: ViewContainerRef }) vcRef: ViewContainerRef;

它将匹配

*ngFor="let track of music | async | sortMusic: sortBy as sortedTracks" 
                     |                                    | 
                      \                                  /
                                   attrValue

但不要使用方括号,例如:

*ngFor="let track of music | async | sortMusic: [sortBy] as sortedTracks"

因为选择器

@Directive({
  selector: '[ngForOf=music | async | sortMusic: [sortBy] ]'
})

行不通。