Search code examples
angularangularjs-ng-transclude

Angular2: Passing multi-slot transcluded content to children components as parameters


I am having and article component prefixed with b-...

<b-article>

and inside I have some custom elements

  1. b-title
  2. b-photo
  3. b-summary

using like this:

<b-article-item>
    <b-title>My Article Title</b-title>
    <b-photo>http://placehold.it/1280X720</b-photo>
    <b-summary>some new content</b-summary>
</b-article-item>

so, if I wouldn't have some more components in the article-item (and no photo) then it would be fairly easy:

<div class="article">
    <h2><ng-content select="b-title"></ng-content></h2>
    <p class="summary"><ng-content select="b-summary"></ng-content></p>
</div>

but, already it get's complicated with the photo, where the src is as attribute

<div class="article">
    <img src="{{photo}}">
    <h2><ng-content select="b-title"></ng-content></h2>
    <p class="summary"><ng-content select="b-summary"></ng-content></p>
</div>

My structure is a bit more complicated, but doesn't make much difference in logic....

<div class="article">
    <b-thumbnail
        [photo] = "photo"
        [isResponsive] = "true"
    ></b-thumbnail>
    <b-excerpt
        [title]="title"
        [summary]="summary"
    ></b-excerpt>
</div>

HOW, do I get the b-photo's inner HTML as article-item's property...

Worth mentioning that b-photo, b-title and b-summary are not actual components, just custom tags (using CUSTOM_ELEMENTS_SCHEMA to allow them)

Any ideas?

I tried to put this in the article item constructor

constructor(private el:ElementRef){
    let ref = this.el.nativeElement;

    let photos = ref.getElementsByTagName('b-photo');

    if(photos.length > 0){
        this.photo = photos[0].innerHTML;
    }
}

Don't get an ewxpected result, the length is 0


Solution

  • It's definitely not how it should be done in Angular2 because it requires reading from the DOM and causes issues when server-side rendering and WebWorker features should be used.

    This should work though:

    <div class="article">
        <span #wrapper><ng-content select="b-photo"></ng-content></span>
    </div>
    
    export class BArticleItem {
      @ViewChild('wrapper') wrapper:ElementRef;
    
      ngAfterContentInit() {
        this.photo = this.wrapper.nativeElement.querySelector('b-photo').innerHTML;
      }
    }