Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass ng-content to child component

thanks for your time.

I have three component:

  1. Main page component
  2. A button who use angular/cdk/overlay overlay.create to create the third component
  3. A small box attached to the button who display text

The goal is to display information about the page when the user clicks on the button. I can't use @Input, cause the format (h1, p, component) of the information will change for each page.

My question

How can I pass HTML from the main component to the small box component?

or

How can I intercept the content of the ng-content and send it to the small box component?

Main

<app-btn-info>
   <mat-icon>info</mat-icon>
   <h1>Test</h1>
   <p>This is a test</p>
</app-btn-info>

Button

@Component({
  selector: 'app-btn-info',
  templateUrl: './btn-info.component.html',
  styleUrls: ['./btn-info.component.scss']
})
export class BtnInfoComponent {

  @ViewChild('button') button: MatIcon;

  constructor(private overlay: Overlay) { }

  public onClick() {
    this.overlay.create({
      positionStrategy: this.overlay.position().connectedTo(this.button._elementRef,
        { originX: 'start', originY: 'top' }, { overlayX: 'start', overlayY: 'top' }
      )
    });
  }

}
<button #button mat-icon-button color="warn" matTooltip="Choose an option" (click)="onClick()">
    <mat-icon>refresh</mat-icon>
</button>

Small box

<!-- From Main Component - But open by BtnInfoComponent -->
<ng-content></ng-content> 
like image 768
The224 Avatar asked Mar 06 '19 16:03

The224


People also ask

How do you pass data from parent to child component in Angular 14?

Pass data from parent to child component using @Input() decorator, which allows data to pass through templates and child to parent component using @Output() decorator with the help of Event Emitter. Create a new Angular project using the following NPM command: ng new componentSharing.


1 Answers

For future reference if anyone gets here, this may help - https://stackblitz.com/edit/angular-ivy-apjclv?file=src/app/child/child.component.html

Edit:

Basically, what you're looking for in the container:

<app-parent>
<span> some content from container </span>
</app-parent>

and in the parent:

<app-child>
  <ng-content select="[foo]" ngProjectAs="[foo]"> </ng-content>
</app-child>

and in the child:

<ng-content select="[foo]"> </ng-content>

Content can be added in the parent, but you'd need to split it up like:

<ng-container ngProjectAs="[foo]">
  <span>some parent content</span>
  <ng-content select="[foo]"></ng-content>
<ng-container>

Edit 2: So I got carried away with passing TemplateRefs, to have the ability to access variables from the component projecting the content (aka 'parent' in these examples). Accessing variables deeper than the 'parent' gets to be untenable however. If you need to access child variables, at that point I would suggest using a service/observable instead / rethinking your structure.

TemplateRef Example, using the same container/parent/child structure above:

// parent-foo.component.ts
@Input() templateFooSelector?: TemplateRef<any>;
<!-- container.component.html -->
<app-parent [templateFooSelector]="containerTemplate"></app-parent>

<ng-template #containerTemplate let-parentFoo="parentFoo">
  <div *ngIf="parentFoo.bar"> ParentFoo has variable Bar: {{parentFoo.bar}} </div>
</ng-template>
<!-- parent.component.html -->
<app-child>
  <!-- this ngProjectAs is only necessary if the child uses a 'select="..." ` -->
  <ng-container ngProjectAs="[childSelector]">
    <!-- the ngIfs may be unnecessary, haven't tested without -->
    <ng-content *ngIf="!templateFooSelector" select="[fooSelector]"></ng-content>
    <ng-container *ngIf="templateFooSelector">
      <ng-container *ngTemplateOutlet="templateFooSelector; context: {parentFoo: this}">
      </ng-container>
    </ng-container>
  </ng-container>
<app-child>
like image 141
Josh Leslie Avatar answered Sep 28 '22 21:09

Josh Leslie