Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rendering the components in ContentChildren of Angular

This is my component:

import { Component, OnInit, ContentChildren, QueryList } from '@angular/core';
import { IconBoxComponent } from '../icon-box/icon-box.component';

@Component({
  selector: 'app-three-icon-box',
  templateUrl: './three-icon-box.component.html',
  styleUrls: ['./three-icon-box.component.scss']
})
export class ThreeIconBoxComponent implements OnInit {
  @ContentChildren(IconBoxComponent) boxes: QueryList<IconBoxComponent>;

  constructor() { }

  ngOnInit() {
  }

  ngAfterContentInit() {
    console.log(this.boxes);
  }

}

Its template looks like this:

<div class="row justify-content-center">
  <div class="col-12 col-md-10">
    <div class="row justify-content-center text-center">
      <div *ngFor="let box of boxes" class="col-12 col-sm-4 col-lg-3 offset-lg-1 lz-mb-2 lz-mb-sm-0">
        {{ box }}
      </div>
    </div>
  </div>
</div>

This is how I'm rendering it:

  <app-three-icon-box>
    <app-icon-box icon="#icon-one">content 1</app-icon-box>
    <app-icon-box icon="#icon-two">content 2</app-icon-box>
    <app-icon-box icon="#icon-three">content 3</app-icon-box>
  </app-three-icon-box>

In that second block of code, I'm trying to render the <app-icon-box>, but I can't figure out how. {{ box }} was just an idea of what I'm trying to do, but I just get [object Object].

like image 885
user1807782 Avatar asked Mar 14 '18 21:03

user1807782


People also ask

How does Angular render a component?

Angular gives us the mechanism to render components dynamically through View Container using ComponentFactory. To do this, we need to know the Component Type at the compile time. The most dynamic component rendering mechanism would be the one where we don't know what component will be rendered at the compile time.

What is the purpose of the ContentChildren decorator in this component class?

ContentChildren is a parameter decorator that is used to fetch the QueryList of elements or directives from the content DOM. The QueryList is updated whenever the child element/component is added or removed. The child element reference is set in QueryList just before the ngAfterContentInit lifecycle Hook method.

How do you use ContentChildren?

To use ContentChild , we need to import it first from the @angular/core . import { Component, ContentChild, ContentChildren, ElementRef, Renderer2, ViewChild } from '@angular/core'; Then use it to query the header from the projected content.

What is the difference between ViewChild () and ContentChild ()?

ViewChild is used to select an element from component's template while ContentChild is used to select projected content.


1 Answers

You should use this pattern

  1. Create TemplateMarker Directive to mark which templates you want to pass as parameters (to prevent grabbing other templates).
  2. Inject markers using @ContentChildren.
  3. Render them where you need using NgTemplateOutlet.

Hint: You can render each template multiple times and send them parameters.

Example:

import { Component, Input, Directive, TemplateRef, ContentChildren, QueryList } from '@angular/core';
@Directive({
  selector: '[templateMarker]'
})
export class TemplateMarker {
  constructor(public template: TemplateRef<any>) {}
}
@Component({
  selector: 'template-owner',
  template: `
    <div *ngFor="let marker of markers">
      <i><ng-template [ngTemplateOutlet]="marker.template"></ng-template></i>
    </div>
  `,
})
export class TemplateOwner {
  @ContentChildren(TemplateMarker) markers: QueryList<TemplateMarker>;
}
@Component({
  selector: 'hello',
  template: `<template-owner>
    <div *templateMarker>first template</div>
    <div *templateMarker>second template</div>
  </template-owner>`,
})
export class HelloComponent  {}
like image 195
Ilia Volk Avatar answered Oct 07 '22 03:10

Ilia Volk