Search code examples
javascriptangularhigher-order-componentsrecomposeng-component-outlet

How to pass html element as child in Angular Higher Order Components (HOC)?


I want to pass an HTML element in my Angular Higher Order Component. Right now I'm passing child element as a @Input decorator. My HOC, Main Container is like this.

<div>
 <p> MY EXTRA UI HERE</p>
 <ng-container *ngComponentOutlet="child"></ng-container>
</div>

@Component({
  selector: 'app-main-container',
  templateUrl: './main-container.component.html',
  styleUrls: ['./main-container.component.scss'],
})
export class MainContainerComponent {
  @Input() child
}

In other components I'm using my HOC like this

My Current code:

<app-main-container [child]="child"></app-main-container>

in .ts file I'm passing my child component like this

import { SidebarComponent } from '../sidebar/sidebar.component'
@Component({
  selector: 'app-staff',
  templateUrl: './staff.component.html',
  styleUrls: ['./staff.component.scss'],
})
export class StaffComponent {
  child: any = SidebarComponent
}

Now what I want to do is, something like this in React format

<app-main-container> 
    <app-staff-sidebar></app-staff-sidebar>
</app-main-container>

Solution

  • Given the structure you defined in your question

    <app-main-container> 
        <app-staff-sidebar></app-staff-sidebar>
    </app-main-container>
    

    we can achieve this using ng-content.

    Your main-container.component.html should accept it like so:

    <div class="main-container">
      <ng-content></ng-content> <!-- This will be exchanged with the `<app-staff-sidebar></app-staff-sidebar>` that you passed in.
    </div>
    

    Assuming you want to insert more content that should be rendered a little differently than just by plain yielding, you can use slots represented by the select keyword. It is basically trying to find the provided pattern.

    Calling the structure like so:

    <app-main-container>
      <app-staff-sidebar data-slot-type="right"></app-staff-sidebar>
      <div data-slot-type="left"></div>
    </app-main-container>
    

    And accepting the slots like this:

    <div class="main-container">
      <ng-content select="[data-slot-type=left]"></ng-content>
      <ng-content select="[data-slot-type=right]"></ng-content>
    </div>
    

    The select can match any given pattern. It can be a CSS class, an entire tag or anything else the DOM represents.