首页 文章

在Angular2中使用ngFor进行多次转换

提问于
浏览
6

我试图创建一个名为“ grid ”的小角度组件,它只是使用翻译来重新排列其内容 .

它的模板

网格组件模板(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值的内容映射到具有相同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

1 回答

  • 3

    您可以使用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

相关问题