I'm pretty new in angular2 and I'm trying to make a small angular component called "grid" that simply rearranges its content using transclusion.
Its template
grid component template (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>
And this is part of the parent component that uses it.
parent template
<grid>
<div *ngFor="let item of items; index as i" [attr.grid-item-index]="i">
<span>{{item}}</span>
</div>
</grid>
Here's a Plunker.
But the result displays no content. But using...
<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>
it works fine and the result was as I expected.
A Plunker of this last working case.
Can achieve this result using a ngfor or similar.
I've tried using nth-child css pseudo class to avoid using the index but it doesn't work too.
UPDATE
I've made some progress based on @yurzui (Thanks!!) answer. It allows to map content with an grid-item-index value to the view container with the same grid-item-index value.
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
@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
}
}
}
Check this Plunker
You can use ngTemplateOutlet to achieve this but there is another approach that uses low-level API:
parent.component.html
<grid>
<div *ngFor="let item of items">
<span>{{item}}</span>
</div>
</grid>
Additional directive that will help us to recognize destination index.
@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);
}
}
}
来源:https://stackoverflow.com/questions/44564914/multiple-transclusion-using-ngfor-in-angular2