Create a Structural Directive in Angular

A structural directive works with an instance of a template object. It can conditionally or repeatedly execute that template instance and insert the resulting DOM elements into the page.

There are two key API that a structural directive needs to work with:

  1. TemplateRef – This represents the template instance.
  2. ViewContainerRef – The container where the DOM elements created by the template should be inserted.

In this post we will create a Observable subscriber directive. For every object emitted by the observable the directive will execute the template.

Get Started

Create a project and directive.

ng new simple-app
cd simple-app
ng g d subscribe

Write the Directive Code

Open subscribe.directive.ts. Set the code to this.

import { Directive, TemplateRef, ViewContainerRef, Input } from '@angular/core';
import { Subscription, Observable } from 'rxjs';

@Directive({
  selector: '[appSubscribe]'
})
export class SubscribeDirective {
  private subscription:Subscription

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef) { }

  @Input() set appSubscribe(o: Observable<any>) {
    this.cleanup()
    //Delete all previously inserted content
    this.viewContainer.clear()

    if (o === undefined) {
      return
    }

    this.subscription = o.subscribe(emittedData => {
      this.viewContainer.createEmbeddedView(this.templateRef, {
        $implicit: emittedData
      })
    })
  }

  ngOnDestroy() {
    this.cleanup()
  }

  cleanup() {
    if (this.subscription !== undefined) {
      this.subscription.unsubscribe()
      this.subscription = undefined
    }
  }
}

Use the Directive

Open app.component.ts. Add this import statement at the top.

import { interval, Observable } from 'rxjs';

Write the AppComponent class like this.

export class AppComponent {
  timer:Observable<number>

  start() {
    this.timer = interval(1000)
  }

  stop() {
    this.timer = undefined
  }
}

Open app.component.html. Set the content like this.

<button (click)="start()">Start</button>
<button (click)="stop()">Stop</button>

<p *appSubscribe="timer; let num">Value emitted: {{num}}</p>

Run the application. Click the Start and Stop button to test it out.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.