Reputation: 1292
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
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
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