我正在使用Angular2开发应用程序。我有一个场景,我需要将复杂的数据(对象的数组)从一个组件传递到另一个组件(它们不是父子,它们是两个单独的组件)(使用Router.navigate())。我已经搜索了这一点,大多数结果描述了亲子的组成部分的情况。我已经完成了结果,并找到了这些传递数据的方法。
1)创建共享服务2)作为路由参数
传递第二种方法对我有用(尽管我不喜欢当我拥有复杂的数据时,如上所述)。我无法使用共享服务共享数据。因此,我的问题是,仅在组件处于亲子关系中时,使用服务之间的数据是否有效?另外,让我知道是否还有其他优先的方法可以通过一个组件和另一个组件之间传递数据?
更新:我正在从我的方案中添加一些代码。请让我知道为什么通过共享服务通过数据不起作用的错误。
i有2个组件:1)搜索Component 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());
}
}
我敢肯定有什么问题,但这只是我无法弄清楚。。您的错误是您声明UtilityService
两次:
- 一次在
SearchComponent
的提供商中。 - 一次进入
TransferComponent
的提供商。
您应该仅声明一次服务,以确保两个组件都获得相同的实例。为此,您可以在以下任何一个选项之间进行选择:
- 在
@NgModule
的提供商中声明该服务,在其声明中同时具有SearchComponent
和TransferComponent
。9倍10次这是正确的解决方案! - 在
@Component
的提供商中声明该服务,即SearchComponent
和TransferComponent
的父。这可能是不可行的,具体取决于您的组件树的外观。
以下选项#1,您最终以:
@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 { }
然后在组件的构造函数中注入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) { }
}
您需要区分服务何时来自ngmodule或何时来自其他组件。
基础知识
在Angular2中,您有一个具有亲子关系的组成部分的分层树(如您所知)。同时,所有服务均在喷油器的帮助下注入,这也形成了层次结构树(与组件层次结构并行)。喷油器的树与组件树没有必要的一致,因为为了效率,父母可能会有代理注射器。
如何工作
喷油器的作用是将您在构造函数中定义的服务中摄取并将其注入组件,即找到它,如果找不到的话,请启动并将其提供给您。当您将想要一些服务的构造函数放入构造函数中时,它将从组件到根部(即ngmodule)来查看"注射树",以进行服务。如果喷油器发现此服务有一个定义的提供商,但没有服务实例,它将创建服务。如果没有提供商继续上升。
您到目前为止所看到的
您所看到的是,父组件通过"提供者"服务定义,而在树中搜索服务的喷油器会在树上跃升,找到了提供商,启动服务并给您的子组件。为了使某些子树的所有组件具有相同的服务,您只需要在子树的共同根中定义提供商。如果您想为整个模块提供相同的服务,则需要在模块提供商中定义此服务。这是所谓的 Singleton 服务。
一些额外的
通常,如果您想注入服务,并且找不到扎根,则在编译/运行时会出现错误。但是,如果您定义要注入可选服务,则如果找不到此服务的提供商,则不会失败。
或多或少...
一些有用的链接:
-
https://angular.io/docs/ts/latest/guide/guide/hierarchical-depperency-injoction.html
-
https://blog.thoughtram.io/angular/2015/05/05/depparency-indoction-indoction-in-angular-2.html
您可以使用可观察到的两个组件之间共享数据来实现。
我没有写这篇文章,但它非常有用且易于理解 -
快速的帖子显示了一个使我陷入困境的示例 - 如何在Angular 2/4中的组件之间进行交流。
解决方案是使用可观察的和主体(这是一种可观察的类型)
http://jasonwatmore.com/post/2016/12/01/angular-2-communicating-bet-components-components-with-observable-subject