Reputation: 477
This question is quite simple but I can't get rid of it.
I have a <header>
in parent template and I need it disappear when displaying children template through routing module. What I expect is adding a class to the header tag so I can hide it via CSS. This is what I have:
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app',
template: `
<header [class.hidden]="hide">
<h1>My App</h1>
<ul>
<li><a href="/home"></a></li>
<li><a href="/showoff"></a></li>
</ul>
</header>
<router-outlet></router-outlet>
`
})
export class AppComponent {
hide = false; // <-- This is what I need to change in child component
}
app-routing.module.ts
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './welcome.component';
import { ShowOffComponent } from './show.off.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'showoff', component: ShowOffComponent },
];
export const AppRouting = RouterModule.forRoot(routes, {
useHash: true
});
show.offf.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-showoff',
template: `
<h2>Show Off</h2>
<div>Some contents...</div>
`
})
export class ShowOffComponent {
hide = true; // <-- Here is the problem.
// I don't have any idea how to reach parent variables.
}
Upvotes: 19
Views: 38602
Reputation: 9181
I have bumped into the same phenomena very recently with Angular 6.
I wanted to access and change a variable which is belongs to a parent or a grandparent Component. See the image below. I want to access and change a variable which is belongs to Tom, from Jim (who is a child of Tom) and Sara (who is a grandchild of Tom).
There might be some other solutions but the approach I have used to overcome this is by using ViewContainerRef
. I have to inject the ViewContainerRef
to the Child component's constructor, that I need to access the parent Component and traversed through the parent node (or nodes) to find the parent variable.
Injecting to the constructor,
constructor(private viewContainerRef: ViewContainerRef) { }
Accessing and traversing through to the parent node,
getParentComponent() {
return this.viewContainerRef[ '_data' ].componentView.component.viewContainerRef[ '_view' ].component
}
I have made a StackBlitz example with the scenario that I have given you in the above picture.
https://stackblitz.com/edit/angular-comms
Upvotes: 10
Reputation: 31
Less straightforward, but (imho) more accurate way to achieve this is to use service.
create parent-to-child.service.ts file and create a subject property
export class ParentToChildService { showHeader = new Subject(); }
inject it via a constructor in both parent and child components:
constructor(private ptcService: ParentToChildService ) {}
Bind the header component with ngIf (or you can use ngClass, if you insist on using CSS approach) to the property in its TS file:
html: <header *ngIf="showStatus">
TS: showStatus: boolean = true; // true by default ptcSubscription: Subscription;
On ngInit of the header component subscribe to that subject:
ngOnInit(): { this.ptcSubscription = this.ptcService.showHeader.subscribe( (newStatus: boolean) => { this.showStatus = newStatus }); } ); }
In your child component, whenever you need to hide the <header
>, call next
on the service subject:
this.ptcService.showHeader.next(false); //hiding the header
Upvotes: 0
Reputation: 29614
You can use output emitter
In your child component,
import { Component } from '@angular/core';
@Component({
selector: 'app-showoff',
template: `
<h2>Show Off</h2>
<div>Some contents...</div>
`
})
export class ShowOffComponent {
@Output() onHide = new EventEmitter<boolean>();
setHide(){
this.onHide.emit(true);
}
}
In the parent,
export class AppComponent {
hide = false;
changeHide(val: boolean) {
this.hide = val;
}
}
Add a child to the parent with that event emitter,
<app-showoff (onHide)="changeHide($event)"></app-showoff>
Upvotes: 20
Reputation: 13558
In your app.component.ts
you can check your URL and set hide
variable value as below :
import { Component } from '@angular/core';
import { Router, NavigationStart } from '@angular/router';
@Component({
selector: 'app',
template: `
<header [class.hidden]="hide">
<h1>My App</h1>
<ul>
<li><a href="/home"></a></li>
<li><a href="/showoff"></a></li>
</ul>
</header>
<router-outlet></router-outlet>
`
})
export class AppComponent {
hide = false; // <-- This is what I need to change in child component
constructor(private router: Router){}
public ngOnInit() {
this.router.events.subscribe((events) => {
if (events instanceof NavigationStart) {
if (events.url === '/' || events.url === '/home') {
this.hide = false;
} else {
this.hide = true;
}
}
});
}
}
Upvotes: 3