2

I am new to Angular 2 and RXJS. I have a custom header component with 2 triggers (buttons) which should activate 2 different navigation directives in different parts of the application. I have created a service which registers the 2 different navigation directives and the header component subscribes to this. I wanted to know whats the best way to link the buttons in the header to call the open() and close() functions in each of the directives depending on the trigger that is clicked.

NOTE: Please note that I cannot use ViewChild or ContentChild because the navigation can be anywhere on the page. They can be in a different CustomComponent and are not necessarily children of the header component.

I can think of 2 options:

  1. Create 2 separate Observables/BehaviorSubjects for the 2 navigation directives in the Service and let the header pass the open and close messages to them and have the individual navigation directives subscribe to each of those corresponding Observables.
  2. Use EventEmitters but I am not sure how to use this approach.

Could you please suggest a good way to solve this?

Custom Component containing the Navigation:

@Component({
  selector: 'my-app',

  template: `
    <h1>{{title}}</h1>
    <my-custom-header>
      This is some text inside the header
    </my-custom-header>
    <nav custom-nav-1>Custom Nav 1</nav>
    <nav custom-nav-2>Custom Nav 2</nav>
  `
})
export class AppComponent {
  title = 'Hello!';
}

Header Component:

@Component({
  selector: 'my-custom-header',

  template: `
    <div class="container">
      This is a header
      <ng-content></ng-content>
      <div>Number of Nav Registered: {{noOfNav}}</div>
      <button type="button" (click)="toggleNav1()">Toggle Nav 1</button>
      <button type="button" (click)="toggleNav2()">Toggle Nav 2</button>
    </div>
  `,
  styles: ['.container { border: 1px solid; }'],
})
export class HeaderComponent {
  title = 'Hello!';
  noOfNav = 0;

  constructor(private navService: NavService) {}

  ngOnInit() {
    this.navService._navSubject.subscribe({
      next: (id) => {
        if(id!=0) {
          this.noOfNav++;
        }
      }
    });
  }

  toggleNav1() {
    console.log("Toggle Nav 1");
  }

  toggleNav2() {
    console.log("Toggle Nav 2");
  }
}

NavService:

@Injectable()
export class NavService {
  public _navSubject: BehaviodSubject = new BehaviorSubject<number>(0);

  registerNavId(id: number) {
    this._navSubject.next(id);
  }
}

Nav1Directive

@Directive({
  selector: '[custom-nav-1]'
})
export class NavDirective1 {
  constructor(private navService: NavService) {}

  ngOnInit() {
    this.navService.registerNavId(1);
  }

  isOpen() {
    console.log("isOpen");
  }

  open() {
    console.log("Open Nav");
  }

  close() {
    console.log("Close Nav");
  }
}

Nav2Directive:

@Directive({
  selector: '[custom-nav-2]'
})
export class NavDirective2 {
  constructor(private navService: NavService) {}

  ngOnInit() {
    this.navService.registerNavId(2);
  }

  isOpen() {
    console.log("isOpen");
  }

  open() {
    console.log("Open Nav 2");
  }

  close() {
    console.log("Close Nav 2");
  }
}

Plunker: https://plnkr.co/edit/3ISyH7ESoNlt65J56Yni?p=preview

takeradi
  • 3,661
  • 7
  • 29
  • 53
  • So what's the problem? – micronyks Sep 25 '16 at 04:47
  • I want to know whats the best approach to solve this problem. The Observable way, EventEmitter way or some other approach? – takeradi Sep 25 '16 at 04:48
  • Is it working as expected? I can't see anything when I click two buttons. – micronyks Sep 25 '16 at 04:51
  • as of now I am just logging things. I wanted to know whats the best way to link the click event on the buttons in the header component to call the open() and close() functions in each of the directives. – takeradi Sep 25 '16 at 04:53
  • Then you don't need to do anything of that. you simply can use `ViewChild` to call directives methods from header component. – micronyks Sep 25 '16 at 04:58

1 Answers1

1

Since your components are loosely coupled (don't know each other) and you need some interaction between them, your approach (to use RxJS) is the most corresponding approach to angular2.

Everything goes Reactive now, even Forms.

EventEmitter is good, and simple, when you have output events from reusable components.