2017年3月9日 星期四

[Angular2] Transclusion (ng-content)

 Angular    Transclusion    ng-content   multiple ng-contnet   


Introduction


In AngularJS, we use
ngTransclude to capture what we want to put into directive template in the parent’s markup. (See this sample code on Codepen)


In Angular, ng-content is used for transclusion. In this sample, we will learn
1.  Transclusion with ng-content
2.  Multiple ng-content


Environment

Angular 2.4.0
Angular CLI 1.0.0-beta.31




Implement


Transclusion with ng-content

First take a look at our original parent and child components without transclusion.

Parent component

<div class="width light-gray">
    <ul class="index-list-vertical" id="prodCatsDiv">
      <div *ngFor="let prod of (products$ | async)">
        <main-product [prod]="prod">
        </main-product>
      </div>
    </ul>
</div>


Child component

<li style="min-height:150px;">
  <a href="">{{prod.title}}</a>
  <img src="{{prod.listPhoto}}" alt="{{prod.title}}" width="220" height="99">
  <ul *ngFor="let prod of prod.subProducts; let i = index;">
    <li *ngIf="i<3">{{prod.title}}</li>
  </ul>
  <ul *ngIf="prod.subProducts.length>3" style="text-align: right;">
    <li>... More</li>
  </ul>
</li>






Now let’s say we would like to put a “sub-products count” near each main product’s title like the below picture without sending more information to child component.



 

It’s time to use Transclusion.
Add the markup to the parent compoent and put ng-content on the right place in the child component’s template.


Parent component

<div class="width light-gray">
    <ul class="index-list-vertical" id="prodCatsDiv">
      <div *ngFor="let prod of (products$ | async)">
        <main-product [prod]="prod">
          <button type="button" class="btn-raised btn btn-primary btn-circle btn-xs">
               {{prod.subProducts.length}}
          </button>
        </main-product>
      </div>
    </ul>
</div>


Child component

<li style="min-height:150px;">
  <a href="">{{prod.title}}</a>
  <ng-content></ng-content>
  <img src="{{prod.listPhoto}}" alt="{{prod.title}}" width="220" height="99">
  <ul *ngFor="let prod of prod.subProducts; let i = index;">
    <li *ngIf="i<3">{{prod.title}}</li>
  </ul>
  <ul *ngIf="prod.subProducts.length>3" style="text-align: right;">
    <li>... More</li>
  </ul>
</li>


And the result :




Multiple ng-content

What if there are multiple markup on parent and we should put multiple ng-content on the child?  It’s easy by just give them names.

Let’s try pulling the content in the following picture from child to parent.



Parent component

Add the property names “subProdsCnt” and “more” on the markups.

 <ul class="index-list-vertical" id="prodCatsDiv">
      <div *ngFor="let prod of (products$ | async)">
        <main-product [prod]="prod">
          <button type="button" subProdsCnt class="btn-raised btn btn-primary btn-circle btn-xs">
               {{prod.subProducts.length}}
          </button>

          <ul more *ngIf="prod.subProducts.length>3" style="text-align: right;">
            <li>... More</li>
          </ul>
        </main-product>
      </div>
</ul>


Child component

Use the property: select,  to map the parent’s markups.

<li style="min-height:150px;">
  <a href="">{{prod.title}}</a>
  <ng-content select="[subProdsCnt]"></ng-content>
  <a href="">
    <img src="{{prod.listPhoto}}" alt="{{prod.title}}" width="220" height="99">
  </a>
  <ul *ngFor="let prod of prod.subProducts; let i = index;">
    <li *ngIf="i<3">{{prod.title}}</li>
  </ul>
  <ng-content select="[more]"></ng-content>
</li>


That makes multiple ng-content work fine.




Reference



沒有留言:

張貼留言