使用服务 Angular 在组件之间传递数据

Posted

技术标签:

【中文标题】使用服务 Angular 在组件之间传递数据【英文标题】:Passing data between components using a service Angular 【发布时间】:2019-03-20 18:12:27 【问题描述】:

网上有很多关于这个主题的例子,但没有一个对我有帮助。这是场景:我有 2 个组件和一个服务。这两个组件不是父/子,而是 2 个独立的组件。其中一个有一个名称列表,另一个应该在单击其中一个名称时加载一个表格。这是我的home.html 两个组件

<div class="material-docs-app">
  <div class="docs-primary-header">
      <h1>Yep!</h1>
  </div>
    <div fxLayout="row" fxLayout.xs="column" class="component-layout-body">
        <app-heroes-sidenav></app-heroes-sidenav>
        <app-heroes-table #heroesTable fxFlex="1 2 calc(15em + 20px)" style="width: 100%"></app-heroes-table>
    </div>
</div>

Heroes sidenav 组件:

<div *ngIf="loadingData == true">
  <mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
<nav *ngIf="loadingData == false">
  <p *ngFor="let item of heroesNames.results let i = index" [attr.data-index]="i">
    <button mat-button (click)="getHero(i)">
        item.name 
    </button>
  </p>
</nav>

点击时getHero() 被正确调用。这是sidenav组件ts:

import  Component, OnInit, Input  from '@angular/core';
import SwCharactersServiceService from '../sw-characters-service.service';
import HeroesTableComponent from '../heroes-table/heroes-table.component';

@Component(
  selector: 'app-heroes-sidenav',
  templateUrl: './heroes-sidenav.component.html',
  styleUrls: ['./heroes-sidenav.component.css']
)
export class HeroesSidenavComponent implements OnInit 
  heroesNames: any;
  heroData:any;
  loadingData = true;
  @Input() heroesTable: HeroesTableComponent;
  constructor(private _swService: SwCharactersServiceService)  

  ngOnInit() 
    this.getHeroes();
  

  getHeroes() 
    this._swService.getCharacters().then(result => 
      this.loadingData = false;
      this.heroesNames = result;
    );
  

  getHero(index) 
    this._swService.getHero(index);
  

这就是服务:

import  Injectable  from '@angular/core';
import  HttpClient, HttpHeaders  from '@angular/common/http';

import 'rxjs/add/operator/map'

import Observable from 'rxjs/Observable';

@Injectable(
  providedIn: 'root'
)
export class SwCharactersServiceService 
  param:any;
  constructor(private http: HttpClient)  

  getCharacters(): Promise<any[]> 
    return this.http.get<any[]>("https://swapi.co/api/people/")
    .toPromise()
    .then(result => result) 
    .catch(this.handleError);
  

  getHero(index): Observable<any>
    console.log(index);
    let headers = new HttpHeaders();
    headers.append('Content-Type', 'application/json');
    return this.http.get("https://swapi.co/api/people/" + index, 
        headers: headers
    ).map(res => res );
  

  private handleError(error: any): Promise<any> 
    console.error('An error occurred', error); // for demo purposes only
    return Promise.reject(error.message || error);
  

我可以正确看到console.log(index),但请求不起作用。 chrome 控制台网络选项卡中没有发起请求。 这是带有表格的组件:

import  Component, OnInit, Input, Output, EventEmitter  from '@angular/core';
import  Subscription  from 'rxjs/Subscription';
import SwCharactersServiceService from '../sw-characters-service.service';

@Component(
  selector: 'app-heroes-table',
  templateUrl: './heroes-table.component.html',
  styleUrls: ['./heroes-table.component.css']
)
export class HeroesTableComponent implements OnInit 
  loadingData = true;
  heroData :any;
  subscription: Subscription;

  constructor(private _swService: SwCharactersServiceService) 
    this.subscription = this._swService.getHero(1).subscribe(result =>  this.heroData = result; );
    console.log(this.heroData);
  

  ngOnInit() 

  

  ngOnDestroy() 
    // unsubscribe to ensure no memory leaks
    this.subscription.unsubscribe();
  

现在有2个问题:

1) 如您所见,我写了this._swService.getHero(1) 没有传递动态参数。它是如何工作的?如何传递正确的索引?

2) 服务没有触发,我也没有得到任何结果。

还有其他方法吗?

谢谢。

【问题讨论】:

【参考方案1】:

您错过了订阅_swService.getHero()。如果未订阅返回Observable 的方法,则不会调用它。

getHero(index) 
    this._swService.getHero(index).subscribe(
                  (resp) => 
                     // manipulate your response here
                     console.log(resp);  
                  ,
                  (err) => 
          );

【讨论】:

好的,现在可以了,但是接收结果的组件呢? 您的方式已部分纠正。因为我必须将结果传递给另一个组件才能使用该数据创建一个表 请检查更新的代码以处理响应。【参考方案2】:

您可以使用 BehaviourSubject 传递索引值并在单击列表时发送查询请求 在服务中

import  BehaviorSubject  from 'rxjs/BehaviorSubject';
 public index: BehaviorSubject<number> = new BehaviorSubject<number>(null);

在sidenav组件中

getHero(index) 
    this._swService.index.next(index);
  

在英雄表组件中

ngAfterViewInit()
   this._swService.index.subscribe(index=>
      if(index)
        this._swService.getHero(index).subscribe(result =>  this.heroData = result; );
      
   )

【讨论】:

BehaviorSubject 的导入在服务中吗? 是的,索引的声明也是公共索引:BehaviorSubject = new BehaviorSubject(null); 我很高兴能帮上忙 我不知道为什么,但每次点击它会发出 12 个请求。正常吗? getHero() 函数是否仅在 sidenav 组件中调用?

以上是关于使用服务 Angular 在组件之间传递数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在Angular 8中未调用的组件之间传递数据[重复]

Angular2:通过引用传递组件之间的交互

angular2 - 在组件之间传递数据对象

如何在Angular中的路由组件之间传递数据

Angular 用service 在组件间传递数据

如果组件不是Angular2中的父子组件,如何在组件之间传递数据?