0.3.0 • Published 5 months ago

@coreteq/ngx-projection v0.3.0

Weekly downloads
-
License
MIT
Repository
-
Last release
5 months ago

MIT styled with prettier сoreteq

👻 Flexible way to project dynamic content

✨ Ngx-projection library provides NgxContentOutlet standalone structural directive, that allows you to project dynamic content as well as:

  • *ngTemplateOutlet, that creates embedded views based on the TemplateRef template
  • *ngComponentOutlet, that creates a dynamic component based on a reference to the component class
  • or a simple {{ interpolation }} that displays a primitive value tied to a variable in the template

Compatibility with Angular Versions

Table of contents

🚀 Installation

npm install @coreteq/ngx-projection

Setup

Add standalone directive NgxContentOutlet to app NgModule

import { NgxContentOutlet } from '@coreteq/ngx-projection';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, NgxContentOutlet], // <--- you need to add NgxContentOutlet
  bootstrap: [AppComponent]
})
export class AppModule {}

Usage

Use with component class reference

Getting as input a reference to the component class, the *ngxContentOutlet directive dynamically instantiates the component and inserts its host view into this container.

<ng-container *ngxContentOutlet="component as content">
  {{ content }}
</ng-container>
<!--- or --->
<ng-container *ngxContentOutlet="component"></ng-container>
import { ChildComponent } from './child.component'

export class AppComponent {
  component = ChildComponent;
}

Use with optional custom injector

Optional custom injector that will be used as parent for the component. Defaults to the injector of the current view container.

<ng-container *ngxContentOutlet="component as content; injector: customInjector">
  {{ content }}
</ng-container>
import { ChildComponent } from './child.component';
import { Injector } from "@angular/core";

export class RendererComponent {
  component = ChildComponent;
  customInjector: Injector;

  constructor(injector: Injector) {
    this.customInjector = Injector.create({
      parent: injector,
      providers: [
        {
          provide: SOME_TOKEN,
          useValue: 'Some value',
        },
      ],
    });
  }
}
import { Inject } from "@angular/core";
import { SOME_TOKEN } from './tokens';

export class ChildComponent {
  constructor(@Inject(SOME_TOKEN) token: string) {}
}

Use with TemplateRef

In this case *ngxContentOutlet inserts an embedded view from a prepared TemplateRef

<ng-container *ngxContentOutlet="templateRef"></ng-container>

<ng-template #templateRef>
  <div>
    <p> Well, that's where we met! </p>
  </div>
</ng-template>

Use with a context object

Also, you can attach a context object to the EmbeddedViewRef by context option.

<ng-container *ngxContentOutlet="templateRef; context: context"></ng-container>

<ng-template #templateRef let-name let-message="message">
  <div>
    <p> {{name}}, {{message}} </p>
  </div>
</ng-template>

NOTE: Using the key $implicit in the context object will set its value as default. Read more

export class AppComponent {
  readonly context = { $implicit: 'Houston', message: 'we have a problem' };
}

Use with optional custom injector

You can pass a custom injector to be used within the embedded view.

ParentComponent

<!--- ParentComponent provides his own injector to the content --->
<ng-container *ngxContentOutlet="content as implicit; injector: parentInjector">
  {{ implicit }}
</ng-container>
import { inject, Input } from "@angular/core";
import { ReflectiveContent } from "@coreteq/ngx-projection";

export class ParentComponent {
  @Input()
  content: ReflectiveContent<any>;

  parentInjector = inject(Injector);
}

NOTE: See ReflectiveContent type

AppComponent

<app-parent [content]="templateRef"></app-parent>

<ng-template #templateRef>

#### ChildComponent
```ts
import { ParentComponent } from "./parent.component";
import { Inject } from "@angular/core";

export class ChildComponent {
  constructor(@Inject(ParentComponent) parent: ParentComponent) {}
}

Use with primitive type value

And finally *ngxContentOutlet directive allows to use interpolation to display the primitive value. Thanks to as keyword, you can assign to another variable result of ngxContentOutlet.

<ng-container *ngxContentOutlet="value as content">
  {{ content }}
</ng-container>
export class AppComponent {
  // primitive 'string'
  // also *ngxContentOutlet accepts 'number', 'undefined' and 'null'
  value = 'A Cold Day in Hell';
}

API

InputTypeDefaultRequiredDescription
[ngxContentOutlet]ReflectiveContent<T>n/ayes
[ngxContentOutletContext]Record<string, unknown>n/ano
[ngxContentOutletInjector]Injectorn/ano
[ngxContentOutletContent]any[][]n/ano

ReflectiveContent is a union type:

export type ReflectiveContent<T> =
| Type<T>
| TemplateRef<Partial<T>>
| string
| number
| null
| undefined;