This is the 4th day of my participation in the August More Text Challenge

preface

In this article we will cover the final piece on component basics. Content projection is very similar to slots in Vue, and is very useful for component encapsulation. Let’s take a look.

The body of the

1. Project a piece of content

  1. The container component is written like this
<div>No. 1<ng-content></ng-content>
</div>
Copy the code
  1. Business components are used this way
<app-page-container>Content that does not specify a projection location is projected onto a region without the SELECT attribute</app-page-container>
Copy the code

2. Project multiple pieces of content/components

  1. The container component is written like this
    1. Use the label to lock the projection position
    2. Use class to lock the projection position
    3. Lock the projection location with the custom component name
    4. Lock the projection position with custom properties
<div>No. 2<ng-content select="h3"></ng-content>
  <ng-content select=".my-class"></ng-content>
  <ng-content select="app-my-hello"></ng-content>
  <ng-content select="[content]"></ng-content>
</div>
Copy the code
  1. Business components are used this way
<app-page-container>
  <h3>Use the label to lock the projection position</h3>
  <div class="my-class">Use class to lock the projection position</div>
  <app-my-hello>Lock the projection location with the custom component name</app-my-hello>
  <div content>Lock the projection position with custom properties</div>
</app-page-container>
Copy the code
  1. demo

3. Cast shadow elements

Use ng-Container to wrap child elements to reduce unnecessary DOM layers, similar to template in Vue

  1. The container component is written like this
<div>Number 4<ng-content select="question"></ng-content>
</div>
Copy the code
  1. The business component is written like this
<app-page-container>
  <ng-container ngProjectAs="question">
    <p>Is content projection cool?</p>
    <p>Is content projection cool?</p>
    <p>Is content projection cool?</p>
    <p>Is content projection cool?</p>
  </ng-container>
</app-page-container>
Copy the code

4. Conditional content projection

Description of Chinese website:

  1. If your component needs to conditionally render content or render content more than once, it should be configured to accept a ng-template element that contains content to conditionally render.
  2. In this case, the ng-content element is not recommended because it will always be initialized as long as the consumer of the component provides the content, even if the component never defines it or if the ng-content element is inside an ngIf statement.
  3. With the ng-template element, you can have components explicitly render content based on any criteria you want, and render it multiple times. Angular does not initialize the contents of an ng-template element until it is explicitly rendered.
  1. useng-containerDefine our projection block
    1. usengTemplateOutletCommand to renderng-templateElements.
    2. Through built-in dynamic commands*ngIfTo control whether to render the projection.
<div>No. 3<ng-content select="[button]"></ng-content>
  <p *ngIf="expanded">
    <ng-container [ngTemplateOutlet] ="content.templateRef"> </ng-container>
  </p>
</div>
Copy the code
  1. We use in business componentsng-templateTo wrap our actual elements.

The my-Hello component just logs out to ngOnInit() to see what happens.

<app-page-container>
  <div button>
    <button appToggle>switch</button>
  </div>
  <ng-template appContent>
    <app-my-hello>Conditional content projection ~</app-my-hello>
  </ng-template>
</app-page-container>
Copy the code
  1. Now you can see that the page doesn’t render as smoothly as before, because our logic hasn’t colluded yet. Let’s move on. Create a directive and register it with the NgModule to use it

Instructions need to be registered

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

@Directive({
  selector: '[appContent]',})export class ContentDirective {
  constructor(public templateRef: TemplateRef<unknown>){}}Copy the code
  1. We define another directive to control the identity shown/hidden in the component

Instructions need to be registered

@Directive({
  selector: '[appToggle]',})export class ToggleDirective {
  @HostListener('click') toggle() {
    this.app.expanded = !this.app.expanded;
  }
  constructor(public app: PageContainerComponent){}}Copy the code
  1. Declare the content directive we just defined in our container component. The page does not currently report an error
export class PageContainerComponent implements OnInit {

  expanded: boolean = false;

  @ContentChild(ContentDirective) content! : ContentDirective; }Copy the code
  1. You can see from the log that we are switching container componentsexpandedIndicates that only the state is onmy-helloThe component is initialized, this one down herengIfThe rendered content is not visible on the page, but the component is actually initialized.
<div *ngIf="false">
  <ng-content *ngIf="false" select="app-my-hello"></ng-content>
</div>
Copy the code

5. @ContentChild & @ContentChildren

Use these two decorators to operate on the projected component

  1. Use annotations to define the projected component in the business component
@ContentChild(HelloWorldComp)
helloComp: HelloWorldComp;

@ContentChildren(HelloWorldComp)
helloComps: QueryList<HelloWorldComp>;
Copy the code
  1. inngAfterContentInit()The hook executes to perform operations on the projected component

6. @ViewChild & @ViewChildren

Use these two decorators to operate on the finger connector child components

  1. Use annotations to define child components within a business component
@ViewChild(HelloWorldComp)
helloComp: HelloWorldComp;
  
@ViewChildren(HelloWorldComp)
helloComps QueryList<HelloWorldComp>;
Copy the code
  1. inngAfterViewInit()The hook executes and operates on the direct child component

conclusion

On the use of components we first write here, writing skills are limited, refuel ~, the next article is going to write about the use of custom instructions.