/ngneat-overview

🤖 A collection of tools to make your Angular views more modular, scalable, and maintainable

Primary LanguageTypeScriptMIT LicenseMIT


npm MIT Commitizen friendly PRs styled with prettier All Contributors ngneat spectator

Overview - The Template for Success in Template Management

Compatibility with Angular Versions

@ngneat/overview Angular
4.x >= 14
3.x >= 13
2.x >= 11 < 13

Installation

npm i @ngneat/overview
yarn add @ngneat/overview

Table of Contents

DynamicView

Use the dynamicView structural directive to render a component, a template, HTML, or default template dynamically.

Let’s say we build a generic error component. What we want is to give our consumers the flexibly to create it by using one of three options:

  • They can choose to use the default template
  • They can choose to use their own text which can be static or dynamic
  • They can choose to pass their own template or component
import { DynamicViewModule, Content } from '@ngneat/overview';

@Component({
  template: `
    <div *dynamicView="view">
      Default view
    </div>
  `,
})
export class ErrorComponent {
  @Input() view: Content | undefined;
}


@NgModule({
  imports: [DynamicViewModule]
})
class ErrorModule {}

You can also pass a context or an injector as inputs to the directive:

<h5>Component</h5>
<ng-container *dynamicView="component; injector: injector"></ng-container>

<h5>Template</h5>
<ng-template #tpl let-title><b>{{ title }}</b></ng-template>

<ng-container 
     *dynamicView="tpl || component; 
     context: { $implicit: 'my title' }">
</ng-container>

If you pass context to a component and the value can be accessed via the injectViewContext function.

Teleporting

Teleporting means rendering a view at a different location from its declaration. There are two cases it might be helpful:

  • Avoid prop drilling to a nested component.
  • Rendering a view at another place in the DOM while keeping its context where it’s defined.

You can read more about this approach in this article.

Use the teleportOutlet directive to define a new outlet. An outlet is an anchor where the view will be projected as a sibling.

import { TeleportModule } from '@ngneat/overview';

@Component({ 
  template: `
    <div class="flex">
      <ng-container teleportOutlet="someId"></ng-container>
    </div>
  `
})
export class FooComponent {
}

@NgModule({
  imports: [TeleportModule]
})
export class FooModule {}

Use the teleportTo directive to teleport the view to a specific outlet:

import { TeleportModule } from '@ngneat/overview';

@Component({ 
  template: `
    <section *teleportTo="someId">
      {{ value }}
    </section>
  `
})
export class BarComponent {
  value = '...'
}

@NgModule({
  imports: [TeleportModule]
})
export class BarModule {}

ViewService

The ViewService provides facade methods to create modular views in Angular. It's been used in various projects like hot-toast, and helipopper.

createComponent

The createComponent method takes a Component, and returns an instance of CompRef:

import { ViewService, CompRef } from '@ngneat/overview';

@Injectable()
class ToastService {
  componentRef: CompRef;

  constructor(private viewService: ViewService) {}

  init() {
   this.componentRef = this.viewService
      .createComponent(HotToastContainerComponent)
      .setInput('defaultConfig', defaultConfig)
      .appendTo(document.body);
  }
}

There are cases where we want to use an Angular component template in a third-party library that takes a native DOM element or a string. In this case, we can use the getRawContent or the getElement method, respectively.

import { ViewService } from '@ngneat/overview';

@Directive()
class ChartDirective{

  constructor(private viewService: ViewService) {}

  createChart(color: string) {
   const ref = this.viewService
      .createComponent(FooTooltip)
      .setInput('color', color)
      .detectChanges(document.body);

     const content = ref.getRawContent();

     ref.destroy();

     Highcharts.chart('container', {
      tooltip: {
        formatter: function() {
          return content;
       },
       useHTML: true
     },
   });
  }
}

createComponent Options

createComponent({
  component: Type<C>;
  injector: Injector;
  environmentInjector: EnvironmentInjector;
  context: Record<string, any>;
  vcr: ViewContainerRef | undefined;
  appRef: ApplicationRef | undefined;
})

If you pass context to a component and the value can be accessed via the injectViewContext function.

createTemplate

The createTemplate method takes a TemplateRef, and returns an instance of ViewRef.

createTemplate({
  tpl: TemplateRef<C>;
  context: C;
  vcr: ViewContainerRef | undefined;
  appRef: ApplicationRef | undefined;
  injector: Injector | undefined;
})

createView

The createView method takes a Component, a TemplateRef or a string, and creates a View:

import { ViewService, Content } from '@ngneat/overview';

@Injectable()
class ToastService {
  constructor(private viewService: ViewService) {}

  createToast(content: Content) {
    const ref = this.viewService.createView(content);
    document.body.appendChild(ref.getElement());
  }
}

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Netanel Basal

💻 🤔

Dharmen Shah

🖋 📖

This project follows the all-contributors specification. Contributions of any kind welcome!

Icons made by Freepik from www.flaticon.com