t" /> t" /> t"/>

Is it possible to pass @Input object to a component using content projection in Angular?

192 Views Asked by At

I want to do something like this in app.component:

<app-table-container [data]="tableData">
  <app-some-table></app-some-table>
</app-table-container>

table-container.component.html

<!-- stuff that also needs data-object -->
<ng-content [data]="data"></ng-content>

table-container.component.ts

@Input() data: ITableStuff;

some-table.component.ts

@Input() data: ITableStuff;

This doesn't work

I can pass the tableData to both in app.component but I'd like to pass it only to table-container and from there to projected content.

2

There are 2 best solutions below

5
Eliseo On

You can "reach" the parent using in constructor of app-some-table and use a getter (not an input)

get data()
{
   return this.tableComponent?this.tableComponent.data:null
}
constructor(@Host() @Optional() private tableComponent:AppTableComponent){}

You can also, instead use a getter assign the value in ngAfterViewOnInit

export class ChildComponent implements AfterViewInit{
  data!:any
  constructor(@Host() @Optional() private tableComponent:ParentComponent){}
  ngAfterViewInit()
  {
    this.data=this.tableComponent?this.tableComponent.data:null
  }
}

See stackblitz (in the stackblitz is the second option, I enclosed in a setTimeout when equal the data to avoid the error "Expression has changed after it was checked")

Update another approach is use ContentChild.

In our parent

 @ContentChild(ChildComponent) child!:ChildComponent

And in ngAfterViewInit

  ngAfterViewInit()
  {
    setTimeout(()=>{
      if (this.child)
        this.child.anotherData=this.data
    })
  }

But this approach need know the "childComponent" class. Always can extends all the possibles child from a component base and ask about "ChildComponentBase"

2
kemsky On

It is not straightforward because of DI hierarchy in this case.

One option is to use ContentChild/ContentChildren to get instance of some-table.component and assign its input in AfterContentInit callback.