Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wrap each child of contentchildren in their own elements in Angular

lets say I want to make a component that arranges all of its children. I should be able to provide the element for example:

<app-layout-list>
  <p>foo</p>
  <p>bar</p>
  <p>etc</p>
</app-layout-list>

and inside the app-layout-list should do something like

<ul>
  <li>
    <ng-content>
  </li>
<ul>

where it generates an li for each content. Is this possible using ng-content or do I need to do something more complicated?

like image 287
Slymodi Avatar asked May 19 '18 01:05

Slymodi


People also ask

What is the difference between View child and content child?

While the ViewChild decorator allows to query for a single element from the view DOM, the ContentChildren decorator queries a list of elements in the content DOM. Difference between view and content DOMs : The view DOM is the HTML directly defined in the component HTML file (for example in settings-panel. component.

What is content children in angular?

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.

What is Viewchildren?

The view children of a given component are the elements used within its template, its view. We can get a reference to these view children in our component class by using the @ViewChild decorator.

How do you use ContentChildren?

Using ContentChild and 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.


1 Answers

Of course you can! :)

And it is very simple! (Directly to the Stackplitz Demo)

Angular provides a perfect API for this kind of problems.

Basically what you want is to splitt your <ng-content></ng-content> in their different parts.

First of all you have to mark the portions you want to display inside the <li> elements via a directive. The best way to achive this is via a Structural Directive, because it generates a <ng-template></ng-template> for us, which we need later.

The Directive we build is very basic. It only injects the TemplateRef in the constructor and saves the template in a `public variable:

list-item.directive.ts

import { Directive, TemplateRef } from '@angular/core';

@Directive({
  selector: '[appListItem]'
})
export class ListItemDirective {

  public itemTemplate: TemplateRef<any>;

  constructor(private templateRef: TemplateRef<any>) {
    this.itemTemplate = this.templateRef;
  }

}

With this directive we mark our html elements which we like to place inside a <li> element.

app.component.ts

<app-layout-list>
  <p *appListItem>foo</p>
  <p *appListItem>bar</p>
  <p *appListItem>etc</p>
</app-layout-list>

Inside LayoutListComponent we get hold of the projected elements via @ContentChildren(ListItemDirective) listItems

layout-list.component.ts

import { Component, ContentChildren, QueryList } from '@angular/core';

@Component({
  selector: 'app-layout-list',
  templateUrl: './layout-list.component.html',
  styleUrls: ['./layout-list.component.css']
})
export class LayoutListComponent {
  @ContentChildren(ListItemDirective) listItems: QueryList<ListItemDirective>;
}

Finally inside the Component template we are iterating through the listItems and placing the TemplateReference of every item inside a ngTemplateOutlet

layout-list.component.html

<ul>
  <ng-container *ngFor="let item of listItems">
    <li>
      <ng-container [ngTemplateOutlet]="item.itemTemplate"></ng-container>
    </li>
  </ng-container>
</ul>

DEMO: Stackblitz Demo

GITHUB SOURCE: Github Source

like image 54
SplitterAlex Avatar answered Oct 13 '22 03:10

SplitterAlex