Обмен данными между компонентами с помощью службы в Angular2
Я разрабатываю приложение с использованием angular2. У меня есть сценарий, где мне нужно передать сложные данные (массив объектов) от одного компонента к другому компоненту(они не являются родительскими-дочерними, они являются двумя отдельными компонентами) при маршрутизации(используя маршрутизатор.плавать.))( Я прогуглил это, и большинство результатов описывают сценарий компонентов, которые являются родительскими. Я просмотрел результаты и нашел эти способы передачи данных.
1) Создать Общую Службу 2) пройти как параметры маршрута
2-й подход работает для меня (хотя мне это не нравится, когда у меня есть сложные данные, как описано выше). Я не могу поделиться данными с помощью shared service. Итак, мои вопросы: передача данных между компонентами с помощью служб работает только тогда, когда компоненты находятся в отношениях "родитель-потомок"? Кроме того, дайте мне знать, есть ли другие предпочтительные способы передачи данных между одним компонентом и другим?
обновление: Я добавляю немного кода из моего сценария. Пожалуйста сообщите мне о моей ошибке, почему передача данных через общие службы не работает.
у меня есть 2 компонента: 1) SearchComponent 2) TransferComponent Я устанавливаю данные в SearchComponent и хочу получить доступ к данным в TransferComponent через utilityService.
Коммунальные Услуги:
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.ТС
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.ТС
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 ответов
камарон прав. Ваша ошибка в том, что вы объявляете 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) для существования службы. Если инжектор обнаруживает, что существует определенный поставщик для этой службы, но не экземпляр службы, он создаст службу. Если нет провайдера, он продолжает расти.
то, что вы видели до сих пор
то, что вы видели, это то, что родительский компонент определяет через "провайдеров" службу, а инжекторы в поисках службы идут одним прыжком вверх по дереву, находит провайдера, инициирует службу и дает вашему дочернему компоненту. Чтобы все компоненты некоторого поддерева имели одну и ту же Службу, вы необходимо определить провайдера только в общем корне поддерева. Если вы хотите иметь одну и ту же услугу для всего модуля, вам нужно определить эту услугу в поставщиках модуля. Это так называемый Синглтон сервис.
дополнительные
обычно, если вы хотите внедрить службу и не смогли найти ее полностью до root, вы получите ошибку во время компиляции/выполнения. Но если вы определяете, что вы хотите ввести дополнительно сервис, инжектор не произойдет сбоя, если поставщик для этой службы не найден.
более или менее...
полезные ссылки:
вы можете достичь путем обмена данными между двумя компонентами с помощью наблюдаемых.
Я не писал этот пост, но его довольно полезно и легко понять -
быстрый пост, чтобы показать пример того, что заставило меня застрять на некоторое время - как общаться между компонентами в Angular 2/4.
решение заключается в использовании наблюдаемого и субъекта (который является типом observable)