Content Projection trong Angular

Photo by Pim Chu on Unsplash

Content Projection trong Angular

·

2 min read

Với những component mà có phần layout giống nhau, có thể khác về 1 số label, content, element thì có thể dùng content projection.

import { Component } from '@angular/core';

@Component({
  selector: 'rio-child',
  template: `
    <div>
      <h4>Child Component</h4>
      <ng-content></ng-content>
    </div>
  `
})
export class ChildComponent {
}

tại component cha

<rio-child>
    <p>My <i>projected</i> content.</p>
  </rio-child>

=> tại component cha khi build ra như sau:

<div>
      <h4>Child Component</h4>
      <p>My <i>projected</i> content.</p>
</div>

Ta thấy nội dung bên trong ở component cha đã thay thế cho ở component con, đây chính là Content Projection.

Trong component con có thể có nhiều thẻ , nhưng điều kiện là các thẻ này phải được đánh dấu là khác nhau, nếu không thì thẻ cuối cùng mới có giá trị, vì nó đè lên các thằng khác.

Tại child component

<div style="...">
  <h4>Child Component with Select</h4>
  <div style="...">
    <ng-content select="header"></ng-content>
  </div>
  <div style="...">
    <ng-content select="section"></ng-content>
  </div>
  <div style="...">
    <ng-content select=".class-select"></ng-content>
  </div>
  <div style="...">
    <ng-content select="footer"></ng-content>
  </div>
</div>

Ta thấy các thẻ trên đánh dấu khác nhau bởi attribute select. Tại component cha cũng phải đặt các giá trị của selector vào thì mới nhận được

<rio-child-select>
  <section>Section Content</section>
// chỗ này sẽ thay thế giá trị <ng-content select="section"></ng-content>(selector=section)
  <div class="class-select">
    <p>class select</p>
// chỗ này sẽ thay thế giá trị <ng-content select="class-select"></ng-content>(selector=class-select)
  </div>
  <footer>Footer Content</footer> 
// chỗ này sẽ thay thế giá trị <ng-content select="footer"></ng-content>(selector=footer)
  <header>Header Content</header>
// chỗ này sẽ thay thế giá trị <ng-content select="header"></ng-content>(selector=header)
</rio-child-select>

ngProjectAs

select hoạt động với ng-content ở cấp lồng nhau đầu tiên của component cha. Nhưng nếu chúng ta lồng ghép nhiều cấp thì nó không hoạt động, do đó cần dùng ngProjectAs - để link đến select nhưng dùng cho component lồng nhau.

@Component({
  selector: 'wrapper',
  template: `
    <div class="box red">
      <ng-content></ng-content>
    </div>
    <div class="box">
      <ng-content select="counter"></ng-content>
    </div>
  `
})
class Wrapper {}
@Component({
  selector: 'my-app',
  template: `
    <wrapper>
      <ng-container ngProjectAs="counter">
        <counter></counter>
      </ng-container>
    </wrapper>
  `,
})
class App {}

Tại App component thì <counter></counter> sẽ thay thế chỗ của <ng-content select="counter"></ng-content>, nếu không có ngProjectAs thì nó sẽ không thay thế được bởi vì có <ng-container></ng-container> bao ngoài <counter></counter>.

https://habr.com/ru/post/491136/ https://medium.com/claritydesignsystem/ng-content-the-hidden-docs-96a29d70d11b