otro - pasar parametros entre componentes angular 4
Compartir datos entre componentes utilizando un servicio en Angular2 (3)
Estoy desarrollando una aplicación usando angular2. Tengo un escenario en el que necesito pasar datos complejos (matriz de objetos) de un componente a otro componente (no son padres-hijos, son dos componentes separados) mientras se enruta (usando router.navigate ()). He buscado en Google esto y la mayoría de los resultados describen el escenario de los componentes que son padre-hijo. He revisado los resultados y he encontrado estas formas de pasar los datos.
1) Crear un servicio compartido 2) Pasar como parámetros de ruta
El segundo enfoque funciona para mí (aunque no me gusta cuando tengo datos complejos como se explicó anteriormente). No puedo compartir los datos utilizando el servicio compartido. Entonces, mi pregunta es, ¿el paso de datos entre componentes que usan servicios solo funciona cuando los componentes están en una relación padre-hijo? Además, avíseme si hay otras formas preferidas de pasar datos entre un componente y otro.
Actualizado: estoy agregando un poco de código de mi escenario. Por favor, hágame saber mi error acerca de por qué no funciona el paso de datos a través de servicios compartidos.
Tengo 2 componentes: 1) SearchComponent 2) TransferComponent Estoy configurando los datos en SearchComponent y quiero acceder a los datos en TransferComponent a través de utilityService.
Servicio de utilidad:
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());
}
}
Estoy seguro de que algo está mal, pero es solo que no puedo resolverlo. Se agradece cualquier ayuda.
Camaron tiene razón. Su error es que declara UtilityService
dos veces :
- Una vez en los proveedores de
SearchComponent
. - Una vez en los proveedores de
TransferComponent
.
Debe declarar el servicio SOLAMENTE UNA VEZ para asegurarse de que ambos componentes obtengan la misma instancia. Para esto puedes elegir entre cualquiera de estas opciones:
- Declare el servicio en los proveedores de un
@NgModule
que tiene tantoSearchComponent
comoTransferComponent
en sus declaraciones . ¡9 de cada 10 veces esta es la solución correcta! - Declare el servicio en los proveedores de un
@Component
que es padre deSearchComponent
yTransferComponent
. Esto podría no ser factible dependiendo de cómo se vea su árbol de componentes.
Siguiendo la opción # 1, terminas con:
@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 { }
Luego inyecte UtilityService
en los constructores de sus componentes SIN REDUCIRLO EN LOS proveedores de los componentes:
@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) { }
}
Debe distinguir cuándo el servicio es de NgModule o cuando proviene de otro Componente.
Lo esencial
En Angular2 tienes un árbol jerárquico de componentes con relación padre-hijo (como notaste). Al mismo tiempo, todos los servicios se inyectan con la ayuda de inyectores, que también forman un árbol de jerarquía (en paralelo a la jerarquía de componentes). El árbol de inyectores no coincide necesariamente con el árbol de componentes, ya que podría haber inyectores proxy de la matriz para fines de eficiencia.
Cómo funciona
El rol de los inyectores es tomar el servicio que usted define en el constructor e inyectarlo en su componente, es decir, buscarlo, iniciarlo si no lo encuentra y proporcionárselo. Cuando ponga en el constructor que desea algún servicio, buscará la existencia del servicio en el árbol de inyectores desde su componente hasta la raíz (que es NgModule). Si el inyector encuentra que hay un proveedor definido para este servicio pero no una instancia de servicio, creará el servicio. Si no hay proveedor sigue subiendo.
Lo que has visto hasta ahora
Lo que ha visto es que el componente primario define a través de "proveedores" el servicio, y los inyectores que buscan el servicio se suben a un árbol, encuentran al proveedor, inician el servicio y le dan a su componente secundario. Para que todos los componentes de algún subárbol tengan el mismo Servicio, debe definir el proveedor solo en la raíz común del subárbol. Si desea tener el mismo servicio para el módulo completo, necesita definir este servicio en los proveedores del módulo. Este es el llamado servicio Singleton .
Algo extra
Normalmente, si desea inyectar el servicio y no puede encontrarlo hasta la raíz, obtendrá un error durante la compilación / tiempo de ejecución. Pero si define que desea inyectar el servicio opcional , el inyector no fallará si no se encuentra el proveedor para este servicio.
Más o menos...
Algunos enlaces útiles:
Se podría lograr compartiendo datos entre dos componentes utilizando Observables.
No escribí este post pero es bastante útil y fácil de entender.
Una publicación rápida para mostrar un ejemplo de algo que me atascó por un rato: cómo comunicarme entre los componentes en Angular 2/4.
La solución es usar un observable y un sujeto (que es un tipo de observable)