En una de mis plantillas de rutas Angular 2 ( FirstComponent ) tengo un botón
first.component.html
<div class="button" click="routeWithData()">Pass data and route</div>
Mi objetivo es lograr:
Haga clic en el botón -> ruta a otro componente conservando los datos y sin utilizar el otro componente como directiva.
Esto es lo que intenté ...
1er ENFOQUE
En la misma vista, estoy almacenando la recopilación de los mismos datos en función de la interacción del usuario.
first.component.ts
export class FirstComponent {
constructor(private _router: Router) { }
property1: number;
property2: string;
property3: TypeXY; // this a class, not a primitive type
// here some class methods set the properties above
// DOM events
routeWithData(){
// here route
}
}
Normalmente me encaminaría a SecondComponent por
this._router.navigate(['SecondComponent']);
eventualmente pasando los datos por
this._router.navigate(['SecondComponent', {p1: this.property1, p2: property2 }]);
mientras que la definición del enlace con parámetros sería
@RouteConfig([
// ...
{ path: '/SecondComponent/:p1:p2', name: 'SecondComponent', component: SecondComponent}
)]
El problema con este enfoque es que supongo que no puedo pasar datos complejos (por ejemplo, un objeto como property3) en la url;
2do ENFOQUE
Una alternativa sería incluir SecondComponent como directiva en FirstComponent.
<SecondComponent [p3]="property3"></SecondComponent>
Sin embargo, quiero dirigirme a ese componente, ¡no incluirlo!
3er ENFOQUE
La solución más viable que veo aquí sería utilizar un servicio (por ejemplo, FirstComponentService) para
Si bien este enfoque parece perfectamente viable, me pregunto si esta es la forma más fácil / elegante de lograr el objetivo.
En general, me gustaría saber si me faltan otros enfoques potenciales para pasar los datos entre componentes, particularmente con la menor cantidad posible de código.
actualización 4.0.0
Consulte los documentos de Angular para obtener más detalles https://angular.io/guide/router#fetch-data-before-navigating
original
Usar un servicio es el camino a seguir. En los parámetros de ruta, solo debe pasar los datos que desea que se reflejen en la barra de URL del navegador.
Consulte también https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service
El enrutador enviado con RC.4 vuelve a introducir data
constructor(private route: ActivatedRoute) {}
const routes: RouterConfig = [
{path: '', redirectTo: '/heroes', pathMatch : 'full'},
{path : 'heroes', component : HeroDetailComponent, data : {some_data : 'some value'}}
];
class HeroDetailComponent {
ngOnInit() {
this.sub = this.route
.data
.subscribe(v => console.log(v));
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}
Consulte también Plunker en https://github.com/angular/angular/issues/9757#issuecomment-229847781
Creo que dado que no tenemos el tipo de cosa $ rootScope en angular 2 como en angular 1.x. Podemos usar el servicio / clase compartido angular 2 mientras que en ngOnDestroy pasar datos al servicio y después del enrutamiento tomar los datos del servicio en la función ngOnInit :
Aquí estoy usando DataService para compartir el objeto héroe:
import { Hero } from './hero';
export class DataService {
public hero: Hero;
}
Pasar objeto del componente de la primera página:
ngOnDestroy() {
this.dataService.hero = this.hero;
}
Tomar objeto del componente de la segunda página:
ngOnInit() {
this.hero = this.dataService.hero;
}
Aquí hay un ejemplo: plunker
Angular 7.2.0 introdujo una nueva forma de pasar los datos al navegar entre componentes enrutados:
@Component({
template: `<a (click)="navigateWithState()">Go</a>`,
})
export class AppComponent {
constructor(public router: Router) {}
navigateWithState() {
this.router.navigateByUrl('/123', { state: { hello: 'world' } });
}
}
O:
@Component({
selector: 'my-app',
template: `
<a routerLink="/details" [state]="{ hello: 'world' }">Go</a>`,
})
export class AppComponent {}
Para leer el estado, puede acceder a la window.history.state
propiedad una vez finalizada la navegación:
export class PageComponent implements OnInit {
state$: Observable<object>;
constructor(public activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.state$ = this.activatedRoute.paramMap
.pipe(map(() => window.history.state))
}
}
<div class="button" click="routeWithData()">Pass data and route</div>
bueno, la forma más fácil de hacerlo en angular 6 u otras versiones, espero es simplemente definir su ruta con la cantidad de datos que desea pasar
{path: 'detailView/:id', component: DetailedViewComponent}
como puede ver en la definición de mis rutas, agregué el /:id
to stand a los datos que quiero pasar al componente a través de la navegación del enrutador. Por lo tanto, su código se verá como
<a class="btn btn-white-view" [routerLink]="[ '/detailView',list.id]">view</a>
para leer id
el componente, solo importe ActivatedRoute
como
import { ActivatedRoute } from '@angular/router'
y en el ngOnInit
es donde recuperas los datos
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
this.id = params['id'];
});
console.log(this.id);
}
puede leer más en este artículo https://www.tektutorialshub.com/angular-passing-parameters-to-route/
Estamos en 2019 y muchas de las respuestas aquí funcionarían, dependiendo de lo que quieras hacer. Si desea pasar algún estado interno no visible en la URL (parámetros, consulta), puede usar state
desde 7.2 (como aprendí hoy :)).
Desde el blog (créditos de Tomasz Kula): navegas hasta la ruta ...
... de ts: this.router.navigateByUrl('/details', { state: { hello: 'world' } });
... desde plantilla HTML: <a routerLink="/details" [state]="{ hello: 'world' }">Go</a>
Y para recogerlo en el componente de destino:
constructor(public activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.state$ = this.activatedRoute.paramMap
.pipe(map(() => window.history.state))
}
Tarde, pero espero que esto ayude a alguien con Angular.
Alguna persona súper inteligente (tmburnell) que no soy yo sugiere reescribir los datos de la ruta:
let route = this.router.config.find(r => r.path === '/path');
route.data = { entity: 'entity' };
this.router.navigateByUrl('/path');
Como se ve aquí en los comentarios.
Espero que alguien encuentre esto útil
Este es el otro enfoque que no es bueno para este problema. Creo que el mejor enfoque es el parámetro de consulta por Router
angular que tiene 2 vías:
Pasando el parámetro de consulta directamente
Con este código se puede navegar a url
por params
su código html:
<a [routerLink]="['customer-service']" [queryParams]="{ serviceId: 99 }"></a>
Pasando el parámetro de consulta por
Router
Tienes que inyectar el enrutador dentro de tu me constructor
gusta:
constructor(private router:Router){
}
Ahora usa eso como:
goToPage(pageNum) {
this.router.navigate(['/product-list'], { queryParams: { serviceId: serviceId} });
}
Ahora, si quieres leer desde Router
otro Component
, tienes que usar ActivatedRoute
like:
constructor(private activateRouter:ActivatedRouter){
}
y subscribe
que:
ngOnInit() {
this.sub = this.route
.queryParams
.subscribe(params => {
// Defaults to 0 if no query param provided.
this.page = +params['serviceId'] || 0;
});
}
Solución con ActiveRoute (si desea pasar el objeto por ruta, use JSON.stringfy / JSON.parse):
Prepare el objeto antes de enviarlo:
export class AdminUserListComponent {
users : User[];
constructor( private router : Router) { }
modifyUser(i) {
let navigationExtras: NavigationExtras = {
queryParams: {
"user": JSON.stringify(this.users[i])
}
};
this.router.navigate(["admin/user/edit"], navigationExtras);
}
}
Reciba su objeto en el componente de destino:
export class AdminUserEditComponent {
userWithRole: UserWithRole;
constructor( private route: ActivatedRoute) {}
ngOnInit(): void {
super.ngOnInit();
this.route.queryParams.subscribe(params => {
this.userWithRole.user = JSON.parse(params["user"]);
});
}
}
Miré todas las soluciones (y probé algunas) de esta página, pero no estaba convencido de que tuviéramos que implementar una forma de pirateo para lograr la transferencia de datos entre rutas.
Otro problema con simple history.state
es que si está pasando una instancia de una clase en particular en el state
objeto, no será la instancia mientras la recibe. Pero será un objeto JavaScript simple y llano.
Entonces, en mi aplicación Angular v10 (Ionic v5), hice esto:
this.router.navigateByUrl('/authenticate/username', {
state: {user: new User(), foo: 'bar'}
});
Y en el componente de navegación ( '/authenticate/username'
), en el ngOnInit()
método, imprimí los datos con this.router.getCurrentNavigation().extras.state
-
ngOnInit() {
console.log('>>authenticate-username:41:',
this.router.getCurrentNavigation().extras.state);
}
Y obtuve los datos deseados que se pasaron
El tercer enfoque es la forma más común de compartir datos entre componentes. puede inyectar el servicio del artículo que desea utilizar en el componente relacionado.
import { Injectable } from '@angular/core';
import { Predicate } from '../interfaces'
import * as _ from 'lodash';
@Injectable()
export class ItemsService {
constructor() { }
removeItemFromArray<T>(array: Array<T>, item: any) {
_.remove(array, function (current) {
//console.log(current);
return JSON.stringify(current) === JSON.stringify(item);
});
}
removeItems<T>(array: Array<T>, predicate: Predicate<T>) {
_.remove(array, predicate);
}
setItem<T>(array: Array<T>, predicate: Predicate<T>, item: T) {
var _oldItem = _.find(array, predicate);
if(_oldItem){
var index = _.indexOf(array, _oldItem);
array.splice(index, 1, item);
} else {
array.push(item);
}
}
addItemToStart<T>(array: Array<T>, item: any) {
array.splice(0, 0, item);
}
getPropertyValues<T, R>(array: Array<T>, property : string) : R
{
var result = _.map(array, property);
return <R><any>result;
}
getSerialized<T>(arg: any): T {
return <T>JSON.parse(JSON.stringify(arg));
}
}
export interface Predicate<T> {
(item: T): boolean
}
Pasar usando JSON
<a routerLink = "/link"
[queryParams] = "{parameterName: objectToPass| json }">
sample Link
</a>
utilice un servicio compartido para almacenar datos con un índice personalizado. luego envíe ese índice personalizado con queryParam. este enfoque es más flexible .
// component-a : typeScript :
constructor( private DataCollector: DataCollectorService ) {}
ngOnInit() {
this.DataCollector['someDataIndex'] = data;
}
// component-a : html :
<a routerLink="/target-page"
[queryParams]="{index: 'someDataIndex'}"></a>
.
// component-b : typeScript :
public data;
constructor( private DataCollector: DataCollectorService ) {}
ngOnInit() {
this.route.queryParams.subscribe(
(queryParams: Params) => {
this.data = this.DataCollector[queryParams['index']];
}
);
}
di que tienes
y desea pasar datos a component2.ts .
en component1.ts es una variable con datos dicen
//component1.ts
item={name:"Nelson", bankAccount:"1 million dollars"}
//component1.html
//the line routerLink="/meter-readings/{{item.meterReadingId}}" has nothing to
//do with this , replace that with the url you are navigating to
<a
mat-button
[queryParams]="{ params: item | json}"
routerLink="/meter-readings/{{item.meterReadingId}}"
routerLinkActive="router-link-active">
View
</a>
//component2.ts
import { ActivatedRoute} from "@angular/router";
import 'rxjs/add/operator/filter';
/*class name etc and class boiler plate */
data:any //will hold our final object that we passed
constructor(
private route: ActivatedRoute,
) {}
ngOnInit() {
this.route.queryParams
.filter(params => params.reading)
.subscribe(params => {
console.log(params); // DATA WILL BE A JSON STRING- WE PARSE TO GET BACK OUR
//OBJECT
this.data = JSON.parse(params.item) ;
console.log(this.data,'PASSED DATA'); //Gives {name:"Nelson", bankAccount:"1
//million dollars"}
});
}
Puede utilizar BehaviorSubject para compartir datos entre componentes enrutados. Un BehaviorSubject tiene un valor. Cuando se suscribe emite el valor inmediatamente. Un sujeto no tiene valor.
En el servicio.
@Injectable({
providedIn: 'root'
})
export class CustomerReportService extends BaseService {
reportFilter = new BehaviorSubject<ReportFilterVM>(null);
constructor(private httpClient: HttpClient) { super(); }
getCustomerBalanceDetails(reportFilter: ReportFilterVM): Observable<Array<CustomerBalanceDetailVM>> {
return this.httpClient.post<Array<CustomerBalanceDetailVM>>(this.apiBaseURL + 'CustomerReport/CustomerBalanceDetail', reportFilter);
}
}
En el componente, puede suscribirse a este BehaviorSubject.
this.reportService.reportFilter.subscribe(f => {
if (f) {
this.reportFilter = f;
}
});
Nota: El tema no funcionará aquí, solo es necesario usar el tema de comportamiento.
Una buena solución es implementar un método Guard con canActivate. En este escenario, puede obtener datos de una api determinada y permitir que el usuario acceda al componente descrito en el archivo de enrutamiento. Mientras tanto, se puede establecer la propiedad de datos del objeto de ruta y recuperarla en el componente.
Digamos que tiene esta configuración de enrutamiento:
const routes: Routes = [
{ path: "/:projectName", component: ProjectComponent, canActivate: [ProjectGuard] }
]`
en su archivo de guardia puede tener:
canActivate(next: ActivatedRouteSnapshot,state: RouterStateSnapshot)
: Observable<boolean> | Promise<boolean> | boolean {
return this.myProjectService.getProject(projectNameFoundElsewhere).pipe(
map((project) => {
if (project) {
next.data = project;
}
return !!project;
}),
);
} `
Entonces en tu componente
constructor(private route: ActivatedRoute) {
this.route.data.subscribe((value) => (this.project = value));
}
Esta forma es un poco diferente a pasar a través de un servicio, ya que el servicio mantiene el valor en un sujeto de comportamiento siempre que no esté desarmado. Al pasar por el guardia, los datos están disponibles para la ruta actual. No he comprobado si las rutas de los niños guardan los datos o no.
Por defecto, no usaré un guardia para este para mí, es más, puedo ingresar a la ruta o puedo dejarla. No es para compartir datos entre ellos.
Si desea cargar datos antes de que ingresemos una ruta, simplemente agregue un resolutor a este, esto también es parte del enrutador.
Como ejemplo muy básico:
Resolver
import { Resolve, ActivatedRoute } from "@angular/router";
import { Observable } from "rxjs";
import { Injectable } from "@angular/core";
import { take } from "rxjs/operators";
@Injectable()
export class UserResolver implements Resolve<User> {
constructor(
private userService: UserService,
private route: ActivatedRoute
) {}
resolve(): Observable<firebase.User> {
return this.route.params.pipe(
switchMap((params) => this.userService.fetchUser(params.user_id)),
take(1)
);
}
}
poner en el enrutador:
RouterModule.forChild([
{
path: "user/:user_id",
component: MyUserDetailPage,
resolve: {
user: UserResolver
}
}
}]
obtener los datos en nuestro componente
ngOnInit() {
const user: firebase.User = this.activatedRoute.snapshot.data.user;
}
La desventaja de este enfoque es que ingresará la ruta primero si no obtiene los datos del usuario antes, esto asegura que los datos para el usuario se hayan cargado y estén listos al inicio del componente, pero usted permanecerá en la página anterior como durante mucho tiempo que se han cargado los datos (Cargando animación)
La estrella de HGTV, Christina Hall, revela que le diagnosticaron envenenamiento por mercurio y plomo, probablemente debido a su trabajo como manipuladora de casas.
Recientemente salió a la luz un informe policial que acusa a la estrella de 'Love Is Blind', Brennon, de violencia doméstica. Ahora, Brennon ha respondido a los reclamos.
Conozca cómo Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia mientras organizaba la primera celebración de Acción de Gracias desde que murió su madre, Naomi Judd.
Descubra por qué un destacado experto en lenguaje corporal cree que es fácil trazar "tales paralelismos" entre la princesa Kate Middleton y la princesa Diana.
Los inodoros arrojan columnas de aerosol invisibles con cada descarga. ¿Como sabemos? La prueba fue capturada por láseres de alta potencia.
Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
¿Sigue siendo efectivo ese lote de repelente de insectos que te quedó del verano pasado? Si es así, ¿por cuánto tiempo?
Si este tráiler de pesadilla de la temporada más reciente de Great British Bake Off te asustó y te hizo no volver a ver el programa, es posible que tengas suerte: PBS no ha decidido si se transmitirá o no la última temporada en los Estados Unidos. actualización, para aquellos que no siguen sin aliento este tipo de drama de nicho: el presentador Paul Hollywood y la hermosa carpa llena de batidoras de colores pastel y cuadros se trasladaron de la BBC al Canal 4; Mary Berry, Sue Perkins y Mel Giedroyc renunciaron.
Foto: Netflix Oh, Hello On Broadway (Netflix): Después de llegar a Broadway el año pasado, los dos locos del Upper West Side interpretados por John Mulaney y Nick Kroll finalmente llegaron a Netflix. El especial consta del espectáculo en el escenario, algunos momentos entre bastidores y un invitado muy especial de “Too Much Tuna”.
¿Quiere probar un cepillo de dientes Sonicare sin gastar mucho dinero en uno de sus modelos favoritos de gama alta? Puede comprar un kit de la Serie 2 o Serie 3 por tan solo $ 30 hoy en Amazon. Haga clic aquí para ver la lista completa de modelos elegibles y tenga en cuenta que se descontarán $ 10 adicionales en su carrito.
Tapas elásticas de silicona de Tomorrow's Kitchen, paquete de 12 | $14 | Amazonas | Código promocional 20OFFKINJALids son básicamente los calcetines de la cocina; siempre perdiéndose, dejando contenedores huérfanos que nunca podrán volver a cerrarse. Pero, ¿y si sus tapas pudieran estirarse y adaptarse a todos los recipientes, ollas, sartenes e incluso frutas en rodajas grandes que sobran? Nunca más tendrás que preocuparte por perder esa tapa tan específica.
El equipo está a la espera de las medallas que ganó en los Juegos Olímpicos de Invierno de 2022 en Beijing, ya que se está resolviendo un caso de dopaje que involucra a la patinadora artística rusa Kamila Valieva.
Miles de compradores de Amazon recomiendan la funda de almohada de seda Mulberry, y está a la venta en este momento. La funda de almohada de seda viene en varios colores y ayuda a mantener el cabello suave y la piel clara. Compre las fundas de almohada de seda mientras tienen hasta un 46 por ciento de descuento en Amazon
El jueves se presentó una denuncia de delito menor amenazante agravado contra Joe Mixon.
El Departamento de Policía de Lafayette comenzó a investigar a un profesor de la Universidad de Purdue en diciembre después de recibir varias denuncias de un "hombre sospechoso que se acercaba a una mujer".
Al igual que el mundo que nos rodea, el lenguaje siempre está cambiando. Mientras que en eras anteriores los cambios en el idioma ocurrían durante años o incluso décadas, ahora pueden ocurrir en cuestión de días o incluso horas.
Estoy de vuelta por primera vez en seis años. No puedo decirte cuánto tiempo he estado esperando esto.
“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.
Creo, un poco tarde en la vida, en dar oportunidades a la gente. Generosamente.