【发布时间】:2017-05-26 10:08:02
【问题描述】:
我想从我的共享服务中调用sidenav 组件的方法open()。如果我直接从组件调用该方法,它工作正常。但是,一旦我从共享服务中调用相同的方法,我就会收到一条错误消息:
ERROR TypeError: Cannot read property 'open' of undefined
Sidenav 组件:
import { MdSidenav } from '@angular/material';
import { Component, OnInit, ViewChild } from '@angular/core';
@Component({
selector: 'app-sidebar-content',
template: `
<md-sidenav-container class="container">
<md-sidenav #sidenav class="sidenav">
Jolly good!
</md-sidenav>
<app-main-content></app-main-content>
</md-sidenav-container>
`,
styleUrls: ['./sidebar-content.component.css']
})
export class SidebarContentComponent implements OnInit {
@ViewChild('sidenav') el: MdSidenav;
constructor() { }
ngOnInit() {
}
openSideNav() {
this.el.open();
}
}
共享服务:
import { SidebarContentComponent } from './../content/sidebar-content/sidebar-content.component';
import { Injectable } from '@angular/core';
@Injectable()
export class SharedService {
constructor(private sc: SidebarContentComponent) { }
openSidenav() {
this.sc.openSideNav();
}
}
从另一个组件调用 open 方法:
import { SharedService } from './../../services/shared.service';
import { Component, OnInit } from '@angular/core';
import { SidebarContentComponent } from './../sidebar-content/sidebar-content.component';
@Component({
selector: 'app-main-content',
templateUrl: `
<div class="sidenav-content">
<app-toolbar></app-toolbar>
<button md-button (click)="open()">
Open sidenav
</button>
<button md-button (click)="openWithService()">
Open sidenav with service
</button>
</div>
`,
styleUrls: ['./main-content.component.css']
})
export class MainContentComponent implements OnInit {
constructor(private sc: SidebarContentComponent, private ss: SharedService) { }
ngOnInit() {
}
open() {
this.sc.openSideNav();
// Works fine
}
openWithService() {
this.ss.openSidenav();
// Throws an error
// ERROR TypeError: Cannot read property 'open' of undefined
}
}
【问题讨论】:
-
您没有设置服务的 SidebarContentComponent,这就是它设置为未定义的原因。将它放在构造函数中不起作用:它可以是任何 SidebarContentComponent,即使您可能只有一个。
-
设计错误。服务被注入到组件中,反之亦然。您不能将组件“注入”到服务中。从技术上讲,您可以,因为组件是可注入的类,但它无法正常工作,正如我们在此处看到的那样。
-
@estus 我认为在这种情况下正确的做法是使用 rxjs/subject 并让服务将方法调用传播给它的订阅者。
-
我只想在我的应用程序的任何地方控制sidenav的打开。所以例如如果我在不同的组件中有按钮,我不想每次都注入 sidenav 组件。
-
@Gabriel 然后在您的服务中使用 rxjs 主题并让您的组件(带有 sidenav 的组件)订阅它。