2017-02-19 26 views
0

Ich bin neu in Angular 2 und versuche, ein "onclick" -Ereignis an ein #sitenav-Objekt in einer übergeordneten Komponente/Vorlage zu binden.Angular 2: Eigenschaft 'close' von undefined kann nicht gelesen werden

menu.html (Child template)

<md-list-item *ngFor="let entry of entries"> 
    <button md-menu-item (click)="sidenav.close()"> 
     <md-icon>{{entry.icon}}</md-icon> 
     <span><a routerLink="{{entry.route}}">{{entry.link}}</a></span> 
    </button> 
</md-list-item> 

menu.ts (Child template Komponentendatei)

import { Component } from '@angular/core'; 

@Component({ 
    moduleId:module.id, 
    selector: 'navlinks', 
    templateUrl: 'menubtn.component.html' 
}) 
export class MenuBtnComponent { 
    entries = []; 

@Output() buttonClicked : EventEmitter<any> = new EventEmitter(); 

    close(value:any){ 
    this.buttonClicked.emit("close"); 
    } 

    constructor() {} 

    ngOnInit() { 
    this.entries = [ 
     { 
      icon: 'home', 
      route: '/', 
      link: 'Home' 
     }, 
     { 
      icon: 'sentiment_satisfied', 
      route: '/about', 
      link: 'About Us' 
     }, 
     { 
      icon: 'content_paste', 
      route: '/work', 
      link: 'Out Work' 
     }, 
     { 
      icon: 'mail', 
      route: '/contact', 
      link: 'Get In Touch' 
     }, 
    ]; 

    } 
} 

sitenav.ts (parent template-Komponente)

import {Component, ViewChild, ViewEncapsulation, Directive} from '@angular/core'; 
import { MdMenuModule, MdMenuTrigger} from '@angular/material'; 

import { MenuBtnComponent } from './menubtn.component'; 


@Component({ 
    moduleId:module.id, 
    encapsulation: ViewEncapsulation.Emulated, 
    selector: 'sitenav', 
    templateUrl: './sitenav.component.html', 
    styleUrls: [ './sitenav.component.css'] 
}) 
export class SitenavComponent { 
clickedButton(val){ 
    console.log(val); 
} 
} 

sitenav.html (Muttervorlage)

<!--sidenav--> 
    <md-sidenav 
    #sidenav 
    class="app-sidenav md2 md-sidenav md-sidenav-side md-sidenav-closed" 
    mode="side"> 
    <md-list flex="" role="list" class="flex"> 
     <navlinks (buttonClicked)="close($event)"></navlinks> 
    </md-list> 
    </md-sidenav> 
<!--//sidenav--> 

Die (click)="sidenav.close()" schließen #sitenav auf Klick, scheinen sie sich jedoch nicht von der menu.html Vorlage sichtbar zu sein, so bin ich den Fehler bekommen:

Cannot read property 'close' of undefined 

Wie bin ich in der Nähe von #sidenav?

Antwort

1

Sie können nicht direkt vom untergeordneten Element auf die Methode der übergeordneten Komponenten zugreifen. Output() Parameter ist der beste Weg, um Ihre Anforderung zu erfüllen.

Sie Code hat als

import { Component, Output, EventEmitter } from '@angular/core'; 

@Component({ 
    moduleId:module.id, 
    selector: 'navlinks', 
    templateUrl: 'menubtn.component.html' 
}) 
export class MenuBtnComponent { 
    @Output() buttonClicked : EventEmitter<string> = new EventEmitter<string>(); 
    entries = []; 

    constructor() {} 

    ngOnInit() { 
     .... 

    } 
    close(value:any){ 
    this.buttonClicked.emit("close"); 
    } 
} 

Ihre HTML-Markup geändert werden sollte

<md-list-item *ngFor="let entry of entries"> 
     <button md-menu-item (buttonClicked)="close($event)"> 
     <md-icon>{{entry.icon}}</md-icon> 
     <span><a routerLink="{{entry.route}}">{{entry.link}}</a></span> 
    </button> 
</md-list-item> 

Sie übergeordnete Komponente sollte wie

<md-list-item *ngFor="let entry of entries"> 
     <button md-menu-item (buttonClicked)="close($event)"> 
      <md-icon>{{entry.icon}}</md-icon> 
      <span><a routerLink="{{entry.route}}">{{entry.link}}</a></span> 
     </button> 
</md-list-item> 

Geordnete Komponente ts-Datei die haben sollte unter Methode

clickedButton(val){ 
    console.log(val); 
} 

Hinweis: Die Art und Weise, wie Sie auf die Methode close() zugreifen, gilt für den umgekehrten Fall. ChildComponent Methoden von ParentComponent Es ist ziemlich offensichtlich, dass #sideNav nicht mit der untergeordneten Komponente verwandt ist und wie Sie auf die close() -Methode zugreifen können?

+0

HTML-Markup und Elternkomponente sind die gleichen in Ihrem Code? – HGB

+0

Ich habe den Code oben aktualisiert, aber nichts passiert. Keine Fehler. Sollte ' HGB

+0

Und wie zielt es besonders darauf ab, das #sidenav Element zu schließen? – HGB

0

Eine andere Möglichkeit, dies zu tun, ist durch einen Event-Bus-Service

eventbusservice.ts

import { Subject } from 'rxjs/Rx'; 
import { Observable } from 'rxjs/Observable'; 

export class EventBusService 
{ 
    bus:Subject<Event> = new Subject<Event>(); 

    dispatch(data:Event){ 
     this.bus.next(data); 
    } 

    listen(type:string):Observable<Event> { 
     return this.bus.filter(event=>event.type === type); 
    } 
} 

menu.ts

import { Component, Output, EventEmitter } from '@angular/core'; 
    import { EventBusService } from './eventbusservice' 
@Component({ 
    moduleId:module.id, 
    selector: 'navlinks', 
    templateUrl: 'menubtn.component.html' 
}) 
export class MenuBtnComponent { 
    entries = []; 

    constructor(private eventbus:EventBusService) {} 

    ngOnInit() { 
     .... 

    } 
    close(){ 
    this.eventbus.dispatch("close"); 
    } 
} 

sitenav.ts

import { Component, OnInit } from '@angular/core'; 
import {EventBusService} from './eventbusservice' 

@Component({ 
    moduleId: module.id, 
    selector: 'site-nav', 
    templateUrl: 'sitenav.html' 
}) 
export class SiteNavComponent implements OnInit { 
    constructor(private eventbus:EventBusService) { 
this.eventbus.listen("close").subscribe((e)=>{this.closeSomething()}) 

    } 
closeSomething(){ 

} 
    ngOnInit() { } 
} 

menu.html

<md-list-item *ngFor="let entry of entries"> 
    <button md-menu-item (click)="close()"> 
     <md-icon>{{entry.icon}}</md-icon> 
     <span><a routerLink="{{entry.route}}">{{entry.link}}</a></span> 
    </button> 
</md-list-item> 

Dieser Prozess hilft, bei der Änderung einer Komponente Auswirkungen auf viele anderen Komponenten (nicht nur übergeordnete Komponente) hat.

+0

Interessant. Gibt es einen Grund, keinen Bus Service zu benutzen? Ich habe gerade mit Angular 2 begonnen und möchte so nah wie möglich an den Standards bleiben. Kann eventbusservice.ts jedes Mal importiert werden, wenn Sie auf einer Komponente nach einem Ereignis suchen müssen? – HGB

+0

https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service –

+0

Danke Sai, aber könntest du mit der EventEmitter-Option sagen, was mit meiner obigen Methode los ist? – HGB

Verwandte Themen