angulartransclusionangular2-ngcontent

Passing property to components inside ng-content (properties which aren't available in the component where the markup lies)


I am trying to develop a carousel.

The desired end result should be that the developer would simply write the entire markup in one place (let's say in app.component.html) with only an options property and then, the carousel would take over.

Problem is that from carousel.component I need to set some properties on carousel-item.component (properties that app.component should have nothing to do with... but all the markup is in app.component.html).

How can I achieve this?

app.component.html:

<carousel [options]="myOptions">
    <carousel-item *ngFor="let item of items">
        <img [src]="item.image" alt="" />
    </carousel-item>
</carousel>

<hr />

<carousel [options]="myOptions2">
    <carousel-item *ngFor="let item of items">
        <img [src]="item.image" alt="" />
    </carousel-item>
</carousel>

carousel.component.html:

<div class="carousel-stage">
    <ng-content></ng-content>
</div>

carousel-item.component.html:

<ng-content></ng-content>

Solution

  • I think the only solution is to go with @ContentChildren()

    In my carousel.component.ts:

    import { ContentChildren, ... } from '@angular/core';
    
    // ...
    
    export class CarouselComponent implements AfterContentInit {
      @ContentChildren(ItemComponent) carouselItems;
    
      ngAfterContentInit() {
        this.carouselItems.forEach((item: ItemComponent, currentIndex) => {
          // Do stuff with each item
          // Even call item's methods:
          item.setWidth(someComputedWidth);
          item.setClass(someClass);
        }
      }
    }
    

    Then, in carousel-item.component.ts:

    export class ItemComponent implements OnInit, OnDestroy {
      @HostBinding('style.width') itemWidth;
      @HostBinding('class') itemClass;
      @HostBinding('@fade') fadeAnimationState;
    
    
      setWidth(width) {
        this.itemWidth = width + 'px';
      }
      setClass(class) {
        this.itemClass = class;
      }
      setAnimationState(state) {
        this.fadeAnimationState = state;
      }
    }
    

    Apparently, I can even bind animation triggers with @HostBinding. I assumed @HostBingind() was designed to only work with the standard html attributes (style, class etc.), but it seems that I can actually bind anything (literally anything).

    Does anybody have a better solution? Before I accept my own answer...