Angular2を使用してアプリケーションを開発しています。ルーティング中に(router.navigate()を使用して)あるコンポーネントから別のコンポーネント(親子ではなく、2つの別個のコンポーネント)に複雑なデータ(オブジェクトの配列)を渡す必要があるシナリオがあります。私はこれをグーグルで調べましたが、結果のほとんどは親子であるコンポーネントのシナリオを説明しています。私は結果を調べ、データを渡すこれらの方法を見つけました。
1)共有サービスの作成2)ルートパラメーターとして渡す
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());
}
}
私は何かが間違っていると確信していますが、それは私がそれを理解することができないということだけです。
カマロンは正しい。あなたの間違いはUtilityService
を2回宣言する:
SearchComponent
のプロバイダーに入ったら。TransferComponent
のプロバイダーに入ったら。一度だけサービスを宣言して、両方のコンポーネントが同じインスタンスを取得するようにしてください。このため、次のオプションのいずれかを選択できます。
SearchComponent
とTransferComponent
の両方があるの@NgModule
のプロバイダーでサービスを宣言します。 10回のうち9回が正しい解決策です!SearchComponent
とTransferComponent
の両方の親である@Component
のプロバイダーでサービスを宣言します。これは、コンポーネントツリーの外観によっては実行できない場合があります。オプション#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)までのインジェクターツリーを調べます。インジェクタは、このサービスに対して定義されたプロバイダはあるがサービスインスタンスはないことを検出すると、サービスを作成します。プロバイダーが存在しない場合は、引き続き上昇します。
これまでに見たもの
これまでに見てきたのは、親コンポーネントが「プロバイダー」を通じてサービスを定義し、サービスを検索するインジェクターがツリー内を1ホップ進み、プロバイダーを見つけてサービスを開始し、子コンポーネントに提供することです。あるサブツリーのすべてのコンポーネントが同じサービスを持つようにするには、サブツリーの共通ルートでのみプロバイダーを定義する必要があります。モジュール全体で同じサービスを使用する場合は、モジュールのプロバイダーでこのサービスを定義する必要があります。これは、いわゆるSingletonサービスです。
一部の追加
通常、サービスをインジェクトしたいが、ルートまで完全に見つけられなかった場合、コンパイル/実行中にエラーが発生します。ただし、注入するOptionalサービスを定義した場合、このサービスのプロバイダーが見つからなくてもインジェクターは失敗しません。
多かれ少なかれ...
便利なリンク:
Observablesを使用して2つのコンポーネント間でデータを共有することで実現できます。
私はこの投稿を書きませんでしたが、非常に便利で理解しやすいです-
Angular 2/4。でコンポーネント間で通信する方法-私は少しの間動けなくなった何かの例を示す簡単な投稿。
解決策は、ObservableとSubject(observableの一種)を使用することです