Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access template reference variables from parent in a child?

Tags:

angular

I am trying to get my head around Angular2 and Typescript respectively. What I want to do is open a sidenav from a button which is in a child component - here app-header.

I know I could open it with

<button mat-button (click)="sidenav.open()">Open sidenav</button>

but that would only work if I place this within the parent template as it references the template variable reference sidenav. However, as I said, I want to open it based on a click on a button of a child.

This would be my layout/app template:

<mat-sidenav-container>
  <mat-sidenav #sidenav>
    <!-- sidenav content -->
    Here comes the menu ..
  </mat-sidenav>

  <div>    
    <app-header>
      <!-- Application header -->
    </app-header>
  </div>

</mat-sidenav-container>

And this would be the header template:

<div>
  header for {{title}} works!
  <button mat-button (click)="sidenav.open()">Open sidenav</button>
</div>

Of course this fails because I cannot reference sidenav - so how can I access sidenav from within the child correctly?

Or is passing on such references a "no no" in Angular2 and I should actually use an event based trigger or something like that?

like image 877
Stefan Falk Avatar asked Oct 25 '17 20:10

Stefan Falk


People also ask

How do you access the template variable from the parent component?

You can't access template variable of child components directly. Template variables can only be referenced in the same tamplate you define them. But if you are trying to get the result (confirm/decline) value from the modal child component, you can do it through @Output decorator and EventEmitter s.

How do I access template reference variables?

To get started using template reference variables, simply create a new Angular component or visit an existing one. To create a template reference variable, locate the HTML element that you want to reference and then tag it like so: #myVarName .

How do you pass a template reference variable in a function?

We declare Template reference variables using # followed by the name of the variable ( #variable ). We can also declare them using #variable="customer" when the component/directive defines a customer as the exportAs Property.

How do you use the parent component variable in a child component?

If you want to pass data from the parent component to the child component, you need to use two things: @Input and property binding. In this example, we set in the child component a variable named childExample , which is a string. We set Angular's @Input decorator in front of the variable.


1 Answers

this is normal parent / child component communication. The way you COULD do this is to just expose an output event on the child:

parent.component.html excerpt:

<child-component (openNav)="sidenav.open()"></child-component>

and in the child you just bind the button click to emitting that event:

child.component.ts:

@Output() openNav = new EventEmitter();

child.component.html:

<button (click)="openNav.emit()">Open Nav</button>

HOWEVER, since this is a sidenav that may need to be accessed in a lot of places and maybe even in nested places, you might just want to solve the problem for all situations and use a shared service observable:

side-nav.service.ts:

@Injectable()
export class SideNavService {
    private openNavSource = new Subject(); // never expose subjects directly
    openNav$ = this.openNavSource.asObservable();

    openNav = () => this.openNavSource.next();
}

provide it appropriately, and inject it into the parent and child for use

parent.component.ts:

@ViewChild('sidenav') sidenav; // get your template reference in the component
constructor(private sideNavService: SideNavService) { }
private sideNavSub;
ngOnInit() {
   this.sideNavSub = this.sideNavService.openNav$.subscribe(() => this.sidenav.open());
}
ngOnDestroy() {
   this.sideNavSub.unsubscribe(); //clean your subscriptions
}

child.component.ts:

constructor(private sideNavService: SideNavService) { }
openNav() {
   this.sideNavService.openNav(); // looks repetitive but accessing injectd services in templates is bad practice and will cause pains down the line
}

child.component.html:

<button (click)="openNav()">Open Nav</button>

then you can inject the service into any arbitrary component and use it as needed.

like image 84
bryan60 Avatar answered Oct 14 '22 10:10

bryan60