【问题标题】:Calling component's method from shared service从共享服务调用组件的方法
【发布时间】: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 的组件)订阅它。

标签: angular angular-material


【解决方案1】:

您没有设置服务的 SidebarContentComponent。即使你可以做到,我认为正确的方法是使用 rxjs/Subject。

应该这样做:

共享服务

import { Subject } from 'rxjs/Subject'; // don't forget to import it!

public open$: Subject<any> = new Subject();

侧视图组件

this.sharedService.open$.subscribe(() => this.openSideNav());

任何组件

this.sharedService.open$.next();

【讨论】:

  • 我不知道为什么会收到 Uncaught Error: Can't resolve all parameters for SidebarContentComponent: (?). 错误
  • 我认为这与我的代码无关。这个错误在哪里?
  • 它在 SidenavComponent 中。为了澄清起见,我需要将服务注入到 Sidenav 组件中,然后在 ngOnInit 钩子中订阅主题?
  • 我不看书也不学课程。我从在线文档中学习。你可以得到rxjs的基础知识here,一旦你知道了,你就会通过学习操作符learnrxjs.io来充分利用rxjs。
  • 最常见的运算符也标记为here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2018-05-05
  • 2021-06-05
  • 2012-04-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多