【问题标题】:Multiple transclusion using ngFor in Angular2在 Angular2 中使用 ngFor 进行多重嵌入
【发布时间】:2017-11-17 19:04:29
【问题描述】:

我是 angular2 的新手,我正在尝试制作一个名为“grid”的小型 angular 组件,它使用嵌入来简单地重新排列其内容。

它的模板

网格组件模板(grid.component.ts)

<div class="grid">
  <div class="row">
    <div class="col-xs-4">
      <ng-content select="[grid-item-index=0]"></ng-content>
    </div>
    <div class="col-xs-4">
      <ng-content select="[grid-item-index=1]"></ng-content>
    </div>
    <div class="col-xs-4">
      <ng-content select="[grid-item-index=2]"></ng-content>
    </div>
  </div>
  <div class="row">
    <div class="col-xs-4">
      <ng-content select="[grid-item-index=3]"></ng-content>
    </div>
    <div class="col-xs-4">
      <ng-content select="[grid-item-index=4]"></ng-content>
    </div>
    <div class="col-xs-4">
      <ng-content select="[grid-item-index=5]"></ng-content>
    </div>
  </div>
</div>

这是使用它的父组件的一部分。

父模板

<grid>
  <div *ngFor="let item of items; index as i" [attr.grid-item-index]="i">
    <span>{{item}}</span>
  </div>
</grid>

这是Plunker

但结果显示没有内容。但是使用...

<grid>
  <div grid-item-index="0">item 0</div>
  <div grid-item-index="1">item 1</div>
  <div grid-item-index="2">item 2</div>
  <div grid-item-index="3">item 3</div>
  <div grid-item-index="4">item 4</div>
  <div grid-item-index="5">item 5</div>
</grid>

效果很好,结果如我所料。

最后一个工作案例的Plunker

可以使用 ngfor 或类似工具实现此结果。

我尝试使用 nth-child css 伪类来避免使用索引,但它也不起作用。

更新

根据@yurzui(谢谢!!)的回答,我已经取得了一些进展。它允许将具有 grid-item-index 值的内容映射到具有相同 grid-item-index 值的视图容器。

parent.component.html

<grid>
    <ng-template *ngFor="let item of items; let i=index" 
    [grid-item-index]="(items.length-1)-i">
        <span >{{item}}</span>
    </ng-template> 
</grid>

grid-item-index 指令

@Directive({
  selector: '[grid-item-index]'
})
export class GridItemIndexDirective {
  @Input('grid-item-index') index: any;

  constructor(public vcRef: ViewContainerRef, public tRef: TemplateRef) {}
}

grid.component.ts

@ContentChildren(GridItemIndexDirective) sources: QueryList<GridItemIndexDirective>;
  @ViewChildren(GridItemIndexDirective) containers: QueryList<GridItemIndexDirective>;

  constructor(
    private cdRef:ChangeDetectorRef
  ) {}

  ngAfterViewInit() {
    const len = this.sources.length;
    for (var i = 0; i < len; i++) {
      const destinationContainer = this.containers.find(x => x.index == i);
      const source = this.sources.find(x => x.index == i);
      if (destinationContainer) {
        destinationContainer.vcRef.createEmbeddedView(source.tRef);
        this.cdRef.detectChanges(); // this solves ExpressionChangedAfterItHasBeenCheckedError
      }
    }
  }

检查这个Plunker

【问题讨论】:

标签: angular ngfor transclusion angular2-ngcontent


【解决方案1】:

您可以使用ngTemplateOutlet 来实现此目的,但还有另一种使用低级 API 的方法:

parent.component.html

<grid>
  <div *ngFor="let item of items">
    <span>{{item}}</span>
  </div>
</grid>

帮助我们识别目标索引的附加指令。

@Directive({
  selector: '[grid-item-index]'
})
export class GridItemIndexDirective {
  @Input('grid-item-index') index: any;

  constructor(public vcRef: ViewContainerRef) {}
}

grid.component.html

<div class="grid">
  <div class="row">
    <div class="col-xs-4">
      <ng-template grid-item-index="1"></ng-template>
    </div>
    <div class="col-xs-4">
      <ng-template grid-item-index="2"></ng-template>
    </div>
    <div class="col-xs-4">
      <ng-template grid-item-index="3"></ng-template>
    </div>
  </div>
  <div class="row">
    <div class="col-xs-4">
      <ng-template grid-item-index="4"></ng-template>
    </div>
    <div class="col-xs-4">
      <ng-template grid-item-index="5"></ng-template>
    </div>
    <div class="col-xs-4">
      <ng-template grid-item-index="6"></ng-template>
    </div>
  </div>
</div>

grid.component.ts

@ContentChild(TemplateRef, { read: ViewContainerRef }) vcRef: ViewContainerRef;
@ViewChildren(GridItemIndexDirective) containers: QueryList<GridItemIndexDirective>;

ngAfterViewInit() {
  const len = this.vcRef.length;
  for( var i = 1; i <= len; i++) {
    const destinationContainer = this.containers.find(x => x.index == i);
    if(destinationContainer) {
      const view = this.vcRef.detach(0);
      destinationContainer.vcRef.insert(view);
    }
  }
}

Plunker Example

【讨论】:

  • 是否可以将指令 (item-grid-index) 添加到内容中,以便将其内容映射到视图中的相同 item-grid-index?通过这种方式,您可以更改添加它们的顺序,甚至丢弃没有该指令的内容。
  • 你的意思是像你的原始问题&lt;div *ngFor="let item of items; index as i" [attr.grid-item-index]="i"&gt;
  • 你可能也对这个链接感兴趣stackoverflow.com/questions/44595942/…他也在搭桌子。
  • 是的,我就是这个意思。将具有 grid-item-index 值的内容项与具有相同 grid-item-index 值的视图项匹配。我会看看提到的问题。谢谢。
猜你喜欢
  • 1970-01-01
  • 2023-03-09
  • 2016-05-16
  • 2017-10-31
  • 2017-12-04
  • 2017-07-21
  • 1970-01-01
  • 2017-02-20
  • 1970-01-01
相关资源
最近更新 更多