0

I have an alert directive defined, like so:

import { Component } from 'angular2/core';
import { CORE_DIRECTIVES } from 'angular2/common';
import { Alert } from 'ng2-bootstrap/ng2-bootstrap';

@Component({
  selector: 'alert_directive',
  templateUrl: './shared/directives/alert/alert.html',
  directives: [Alert, CORE_DIRECTIVES]
})
export class AlertDirective {
  alerts:Array<Object> = [ ];

  closeAlert(i:number) {
    this.alerts.splice(i, 1);
  }

  addAlert(message: string, style: string) {
    this.alerts.push({msg: message, type: style, closable: true});
    console.log(this.alerts);
  }
}

I then define my app component where I include this directive:

import {AlertDirective} from '../../shared/directives/alert/alert';
...
@Component({
  selector: 'app',
  templateUrl: './app/components/app.html',
  styleUrls: ['./app/components/app.css'],
  providers: [UserService, HTTP_PROVIDERS],
  encapsulation: ViewEncapsulation.None,
  directives: [ROUTER_DIRECTIVES, AlertDirective]
})
...

This all works, and the directive shows up in the DOM related to my app.html file.

This app.html file contains some global html (navbar, footer, alert_directive). I want alert_directive to be a singleton which I can change the alerts array on to show alert messages from any view without having to add the directive to each view.

So, in another sign in component:

import {Component, ViewEncapsulation} from 'angular2/core';
import {AlertDirective} from '../../shared/directives/alert/alert';
@Component({
  selector: 'sign_in',
  templateUrl: './sign_in/components/sign_in.html',
  styleUrls: ['./sign_in/components/sign_in.css'],
  encapsulation: ViewEncapsulation.Emulated
})
export class SignInCmp {
  alertDirective: AlertDirective;
  constructor(alertDirective: AlertDirective) {
    this.alertDirective = alertDirective;
  }

  showAlert() {
    this.alertDirective.addAlert('test', 'warning');
  }
}

The issue here is I am newing up a new instance of AlertDirective, and therefore my addAlert method is adding to the array of my new instance, not the existing instance which is defined in my app component.

How can I create a directive as a singleton and inject the one single instance into each view, where I can then call any method on that singleton and affect each injected instance?

SnareChops
  • 13,175
  • 9
  • 69
  • 91
JMac
  • 1,726
  • 3
  • 14
  • 30

1 Answers1

3

Create a shared service (only registered in bootstrap()) and use it to communicate between components and your AlertDirective like showb in How do i share data between components in Angular2? The service can also contain an EventEmitter so all participants can subscribe passed messages.

@Injectable()
export class AlertService {
  command: EventEmitter = new EventEmitter();
}

@Component({
  selector: 'alert_directive',
  templateUrl: './shared/directives/alert/alert.html',
  directives: [Alert, CORE_DIRECTIVES]
})
export class AlertDirective {
  constructor(private alertService: AlertService) {
    alertService.commands.subscribe((command) => { doSomething();}
  }
  alerts:Array<Object> = [ ];

  closeAlert(i:number) {
    this.alerts.splice(i, 1);
  }

  addAlert(message: string, style: string) {
    this.alerts.push({msg: message, type: style, closable: true});
    console.log(this.alerts);
  }
}

@Component({
  selector: 'sign_in',
  templateUrl: './sign_in/components/sign_in.html',
  styleUrls: ['./sign_in/components/sign_in.css'],
  encapsulation: ViewEncapsulation.Emulated
})
export class SignInCmp {
  alertDirective: AlertDirective;
  constructor(alertService: AlertService) {
    this.alertService = alertService;
  }

  showAlert() {
    this.sharedService.command.next({text: 'test', title: 'warning'});
  }
}

bootstrap(AppComponent, [/* other providers */, AlertService]);
Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567