最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Displaying content of Component that i fetched with @ContentChildren or @ViewChild - Stack Overflow

programmeradmin5浏览0评论

So I'm trying to display child ponents at specific locations in my Component.

I have the following:

@Component({
  selector: 'app-item-list',
  template: `
<p *ngFor="let item of items">
  {{item.order}}
  <!-- display content of child ponent here -->
</p>`
})
export class ItemListComponent implements OnInit, AfterContentInit {

  //Get all child ponents of the type ItemComponent and store them.
  @ContentChildren(ItemComponent, {descendants: true}) 
  items?: QueryList<ItemComponent>;
  constructor() { }

  ngOnInit() {
  }
    
  ngAfterContentInit(): void {
      
  }

}

@Component({
  selector: 'app-item',
  template: `
<p>
  item works!
</p>
<ng-content></ng-content>
`
})
export class ItemComponent implements OnInit {

  @Input() order?: string;
  constructor() { }

  ngOnInit() {
  }

}

I tried to display it using <ng-content select="item"> but that didn't work.

With the following:

<app-item-list>
  <app-item order="2">
    test2
  </app-item>
  <app-item order="1">
    test1
  </app-item>
</app-item-list>

the expected output is

2
item works!
test2
1
item works!
test1

So I'm trying to display child ponents at specific locations in my Component.

I have the following:

@Component({
  selector: 'app-item-list',
  template: `
<p *ngFor="let item of items">
  {{item.order}}
  <!-- display content of child ponent here -->
</p>`
})
export class ItemListComponent implements OnInit, AfterContentInit {

  //Get all child ponents of the type ItemComponent and store them.
  @ContentChildren(ItemComponent, {descendants: true}) 
  items?: QueryList<ItemComponent>;
  constructor() { }

  ngOnInit() {
  }
    
  ngAfterContentInit(): void {
      
  }

}

@Component({
  selector: 'app-item',
  template: `
<p>
  item works!
</p>
<ng-content></ng-content>
`
})
export class ItemComponent implements OnInit {

  @Input() order?: string;
  constructor() { }

  ngOnInit() {
  }

}

I tried to display it using <ng-content select="item"> but that didn't work.

With the following:

<app-item-list>
  <app-item order="2">
    test2
  </app-item>
  <app-item order="1">
    test1
  </app-item>
</app-item-list>

the expected output is

2
item works!
test2
1
item works!
test1

https://stackblitz./edit/angular-ivy-2aibgt

Share Improve this question edited Jul 30, 2020 at 21:01 Peter asked Jul 16, 2020 at 17:00 PeterPeter 38.6k39 gold badges150 silver badges209 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 9 +100

I can suggest you a solution that is used in Angular material library.

  • Wrap content of app-item ponent in <ng-template> tag

item.ponent.html

<ng-template>  <----------------------------- wrapper
  <p>
    item works!
  </p>
  <ng-content></ng-content>
</ng-template>
  • then we can grab a reference to that TemplateRef

item.ponent.ts

@ViewChild(TemplateRef, {static: true}) template: TemplateRef<any>;
  • finally we can use it in a loop of app-item-list ponent

item-list.ponent.html

<p *ngFor="let item of items">
  {{item.order}}
  <ng-template [ngTemplateOutlet]="item.template"></ng-template>
</p>

Forked Stackblitz

There is really no way to achieve this using ng-content (as far as I know). ng-content is for static content projection only.

Have a look at the use case here - https://github./angular/angular/issues/8563 - paragraph 2 confirms the fact that you have to use a query with viewref to do what you want to do i.e. the solution that @yurzui provided.

You can always use the selector to statically select which part of the content you want to project, but I suspect this is not what you're looking for:

<ng-content select="[order=2]">
</ng-content>
<ng-content select="[order=1]">
</ng-content>

You may missed add select item reference variable in item-list.ponent.html

item.ponent.html

<p>item works</p>
<ng-content select="[body]">
</ng-content>

item-list.ponent.html

<p *ngFor="let item of items">
  <app-item >
  <div body>
      {{item.order}}
  </div>
  </app-item>
  test2
</p>

Ref: Stackblitz example

Take a look at this. Ealier I thought there was not way to achieve your output but I finally figured it out.

What I did was eliminate the @ContentChildren approach and instead replaced it with an items Input passed from the app ponent. I iterated through the items, displaying the order and the corresponding app-item ponent.

发布评论

评论列表(0)

  1. 暂无评论