Yeysides
Yeysides

Reputation: 1292

How to communicate between sibling components when one is being yielded by router outlet

I have a dynamic route /insights/:id in which case my router outlet yields an insight-detail component and I need to display a button on a separate component that navigates back to /insights when clicked. I need this button to only appear when the insight-detail component is displayed. My issue is trying to understand how these two sibling components will communicate. I can have the component that has the button check the url but idk how to do this when the route is dynamic with an id param always changing.

So instead I have this:

  ngOnInit() {
    this.closeIconVisible = false;

    this.router.events.subscribe(res => {
      if (res instanceof NavigationEnd) {
        let fn = this.route.children[0].component;
        let componentName = fn['name'];

        if (componentName === 'InsightDetailComponent') {
          this.closeIconVisible = true;
        } else {
          this.closeIconVisible = false;
        }
      }
    })
  }

This approach works but it doesn't feel right. Any suggestions?

Upvotes: 1

Views: 714

Answers (2)

Yeysides
Yeysides

Reputation: 1292

Taking Gunter's comment into account, I decided to create a shared service that setup a stream between the two sibling components. The final solution looks like this:

First I created a shared service:

import {Injectable} from '@angular/core';
import {Subject} from "rxjs/Subject";

@Injectable()
export class SharedService {

  private closeIconVisible: Subject<boolean> = new Subject<boolean>();

  closeIconVisible$ = this.closeIconVisible.asObservable();

  transmitData(data: boolean) {
    this.closeIconVisible.next(data);
  }

}

Then setup the receiving end of the stream in the component with the button:

this.sharedService.closeIconVisible$
  .takeUntil(this.ngUnsubscribe)
  .subscribe(
    data => {
      this.closeIconVisible = data;
    }
  )

While the other sibling component yielded from the router outlet transmits its existence and passes a value using rxjs Subject observables:

  ngOnInit() {
    this.sharedService.transmitData(true);
  }

Upvotes: 1

Julia Passynkova
Julia Passynkova

Reputation: 17859

You can inject Parent component to a child one and set prop on it. Here is your example:

@Component({
  selector: 'my-parent',
  template: `
    <div>
        parent view
        <button routerLink="/parent" *ngIf="show">close</button>
       <a routerLink="/parent/child">Go Child</a>
    </div>

      <router-outlet></router-outlet>
  `,
})
export class ParentComponent {
  show = false;

  constructor() {}
}

@Component({
  selector: 'my-child',
  template: `
    <div>
      child view
    </div>
  `,
})
export class ChildComponent {
  name:string;
  constructor(private parentComponent: ParentComponent) {}

  ngOnInit() {
    this.parentComponent.show = true;
  }

  ngOnDestroy() {
    this.parentComponent.show = false;
  }
}

@Component({
  selector: 'my-app',
  template: `
    <a routerLink="/parent">Go Parent</a>
    <router-outlet></router-outlet>
  `,
})
export class App {
  name:string;
  constructor() {
    this.name = `Angular! v${VERSION.full}`
  }
}

let routes = [
  {
    path:"parent", 
    component ParentComponent,
    children: [
      {path:"child", component ChildComponent}
    ]
]

Upvotes: 1

Related Questions