使用Angular2中的服务在组件之间共享数据

时间:2017-03-02 23:04:27

标签: angular angular2-routing angular2-components

我正在使用angular2开发一个应用程序。我有一个场景,我需要在路由时使用复杂数据(对象数组)从一个组件传递到另一个组件(它们不是父子,它们是两个独立的组件)(使用router.navigate())。我用Google搜索了这一点,大部分结果都描述了父子组件的场景。我已经完成了结果并找到了传递数据的方法。

1)创建共享服务 2)作为路线参数传递

第二种方法适用于我(尽管如此,当我有如上所述的复杂数据时,我不喜欢这样)。我无法使用共享服务共享数据。 所以我的问题是,使用服务的组件之间传递数据只在组件处于父子关系时才有效吗?另外,让我知道是否还有其他优先方法可以在一个组件和其他组件之间传递数据?

更新: 我在我的场景中添加了一些代码。请让我知道为什么通过共享服务传递数据的错误。

我有2个组件:1)SearchComponent 2)TransferComponent 我在SearchComponent中设置数据,并希望通过utilityService访问TransferComponent中的数据。

公用事业服务:

import {Injectable} from "@angular/core";

@Injectable()
export class UtilityService{
    constructor(){

    }
    public bioReagentObject = [];

    routeBioReagentObj(bioReagentObj){
        console.log("From UtilityService...", bioReagentObj);
        for (let each of bioReagentObj)
            this.bioReagentObject.push(each)
        // console.log("From UtilityService",this.bioReagentObject);
    }

    returnObject(){
        console.log("From UtilityService",this.bioReagentObject);
        return this.bioReagentObject
    }



}

searchcomponent.ts

    import {UtilityService} from "../services/utilityservice.component";
    import {Component, OnInit, OnDestroy, Input} from '@angular/core';

@Component({
    selector: 'bioshoppe-search-details',
    providers: [UtilityService],
    templateUrl: 'app/search/searchdetails.component.html',
    styleUrls: ['../../css/style.css']
})

export class SearchDetailsComponent implements OnInit, OnDestroy {
    constructor(private route: ActivatedRoute,
                private utilityService: UtilityService,
                private router: Router) {

    }
    @Input() selected: Array<String> = [{barcode:123, description:"xyz"}];

       //This method is called from .html and this.selected has the data to be     shared.
       toTransfer() {
        this.utilityService.routeBioReagentObj(this.selected);
        this.router.navigate(['/transfer']);

    }
}

TransferService.ts

import {Component, Input, OnInit, OnDestroy} from '@angular/core';
import {TransferService} from "../services/transferservice.component";
import {UserService} from "../services/userservice.component";
import {SearchService} from "../services/searchservice.component";
import {ActivatedRoute} from '@angular/router';
import {UtilityService} from "../services/utilityservice.component";


@Component({
    selector: 'bioshoppe-transfer',
    providers: [TransferService, UserService, SearchService, UtilityService],
    templateUrl: 'app/transfer/transfer.component.html',
    styleUrls: ['../../css/style.css', '../../css/transfer.component.css']
})

export class TransferComponent implements OnInit, OnDestroy{
    constructor(private transferService: TransferService,
                private userService: UserService,
                private searchService: SearchService,
                private utilityService: UtilityService,
                private route: ActivatedRoute
    ) {

    }
ngOnInit() {
// I am trying to access the data here, but it print "undefind"
console.log("From Transferpage",this.utilityService.returnObject());
}
}

我确信有些事情是错的,但仅仅是因为我无法理解它。感谢任何帮助。

3 个答案:

答案 0 :(得分:23)

camaron是对的。你的错误是你宣布UtilityService两次

  1. 进入SearchComponent
  2. 的提供者
  3. 进入TransferComponent
  4. 的提供者

    您应该仅声明服务ONCE以确保两个组件都获得相同的实例。为此,您可以选择以下任一选项:

    1. @NgModule的提供商中声明服务,在其声明中同时包含SearchComponentTransferComponent。 10次​​中有9次这是正确的解决方案!
    2. @Component的提供商中声明服务,SearchComponentTransferComponent@NgModule({ imports: [CommonModule, ...], // Look, the components injecting the service are here: declarations: [SearchComponent, TransferComponent, ...], // Look, the service is declared here ONLY ONCE: providers: [UtilityService, ...] }) export class SomeModule { } 父级。根据组件树的外观,这可能不太可行。
    3. 按照选项#1,您最终得到:

      UtilityService

      然后在您的组件中注入@Component({ selector: 'foo', template: '...', providers: [] // DO NOT REDECLARE the service here }) export class SearchComponent { constructor(private utilityService: UtilityService) { } } @Component({ selector: 'bar', template: '...', providers: [] // DO NOT REDECLARE the service here }) export class TransferComponent { constructor(private utilityService: UtilityService) { } } &#39;在组件提供商中没有重新构建IT的构造函数:

      (?=city=)[^&]*

答案 1 :(得分:3)

您需要区分服务何时来自NgModule,或何时来自其他组件。

<强>基本

在Angular2中,您有一个具有父子关系的组件的分层树(正如您所注意到的)。同时,所有服务都在注入器的帮助下注入,注入器也形成层次结构树(与组件层次结构并行)。注入器树不必与组件树重合,因为出于效率目的,可能存在来自父节点的代理注入器。

工作原理

注入器的作用是获取您在构造函数中定义的服务并将其注入组件,即找到它,如果找不到则启动并提供给您。当你进入你想要一些服务的构造函数时,它会查看从你的组件到根目录(即NgModule)的注入树,以便服务存在。如果注入器发现此服务已定义提供程序但没有服务实例,则它将创建该服务。如果没有提供者继续上去。

到目前为止您所看到的

您所看到的是,父组件通过“提供者”定义服务,并且搜索服务的注入者在树中跳一跳,找到提供者,启动服务并将其提供给您的子组件。为了使某些子树的所有组件具有相同的服务,您只需要在子树的公共根中定义提供程序。如果要为整个模块提供相同的服务,则需要在模块提供程序中定义此服务。这就是所谓的 Singleton 服务。

一些额外的

通常,如果要注入服务并且无法一直找到root用户,则在编译/运行时会出现错误。但是,如果您定义要注入可选服务,则如果找不到此服务的提供程序,则注入器不会失败。

或多或少......

一些有用的链接:

  1. https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html

  2. https://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular-2.html

答案 2 :(得分:0)

您可以通过使用Observables在两个组件之间共享数据来实现。

我没有写这篇文章,但它非常有用且易于理解 -

一个简短的帖子,展示一些让我陷入困境的例子 - 如何在Angular 2/4中的组件之间进行通信。

解决方案是使用Observable和Subject(这是一种可观察的)

http://jasonwatmore.com/post/2016/12/01/angular-2-communicating-between-components-with-observable-subject