In einer meiner Angular 2-Routenvorlagen ( FirstComponent ) habe ich eine Schaltfläche
first.component.html
<div class="button" click="routeWithData()">Pass data and route</div>
Mein Ziel ist zu erreichen:
Klicken Sie auf die Schaltfläche ->, um zu einer anderen Komponente zu gelangen, wobei die Daten erhalten bleiben und die andere Komponente nicht als Direktive verwendet wird.
Das habe ich versucht ...
1. ANSATZ
In derselben Ansicht speichere ich das Sammeln derselben Daten basierend auf der Benutzerinteraktion.
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
}
}
Normalerweise würde ich nach SecondComponent by routen
this._router.navigate(['SecondComponent']);
schließlich die Daten weitergeben
this._router.navigate(['SecondComponent', {p1: this.property1, p2: property2 }]);
die Definition der Verknüpfung mit Parametern wäre
@RouteConfig([
// ...
{ path: '/SecondComponent/:p1:p2', name: 'SecondComponent', component: SecondComponent}
)]
Das Problem bei diesem Ansatz ist, dass ich denke, ich kann keine komplexen Daten übergeben (z. B. ein Objekt wie property3) in-url;
2. ANSATZ
Eine Alternative wäre das Einfügen von SecondComponent als Direktive in FirstComponent.
<SecondComponent [p3]="property3"></SecondComponent>
Ich möchte jedoch Route zu dieser Komponente, nicht hinzufügen!
dritter Ansatz
Die praktikabelste Lösung, die ich hier sehe, wäre, einen Service (z. B. FirstComponentService) zu verwenden
Obwohl dieser Ansatz durchaus praktikabel erscheint, frage ich mich, ob dies der einfachste/eleganteste Weg ist, um das Ziel zu erreichen.
Im Allgemeinen würde ich gerne wissen, ob mir andere potenzielle Ansätze fehlen um die Daten zwischen Komponenten zu übergeben, insbesondere mit der weniger möglichen Menge an Code
update 4.0.0
Weitere Informationen finden Sie in Angular docs https://angular.io/guide/router#fetch-data-before-navigating
original
Ein Service ist der richtige Weg. In Routenparametern sollten Sie nur Daten übergeben, die in der Browser-URL-Leiste angezeigt werden sollen.
Siehe auch https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service
Der mit RC.4 gelieferte Router führt data
ein
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();
}
}
Siehe auch den Plunker unter https://github.com/angular/angular/issues/9757#issuecomment-229847781
Ich denke, da wir $ rootScope in Winkel 2 nicht so haben wie in Winkel 1.x. Wir können den gemeinsam genutzten Service/die Klasse von Winkel 2 verwenden, während in ngOnDestroy Daten an den Service übergeben werden und nach dem Routing die Daten aus dem Service in die Funktion ngOnInit übernommen werden:
Hier verwende ich DataService, um ein Heldenobjekt zu teilen:
import { Hero } from './hero';
export class DataService {
public hero: Hero;
}
Objekt von der ersten Seitenkomponente übergeben:
ngOnDestroy() {
this.dataService.hero = this.hero;
}
Objekt von zweiter Seitenkomponente übernehmen:
ngOnInit() {
this.hero = this.dataService.hero;
}
Hier ist ein Beispiel: plunker
<div class="button" click="routeWithData()">Pass data and route</div>
nun, der einfachste Weg, dies in eckigen 6 oder anderen Versionen zu tun, hoffe ich, dass Sie einfach Ihren Pfad mit der Datenmenge definieren, die Sie übergeben möchten
{path: 'detailView/:id', component: DetailedViewComponent}
wie Sie aus meiner Routendefinition sehen können, habe ich den /:id
zu den Daten hinzugefügt, die ich per Routernavigation an die Komponente übergeben möchte. Daher wird Ihr Code aussehen
<a class="btn btn-white-view" [routerLink]="[ '/detailView',list.id]">view</a>
um die id
der Komponente zu lesen, importieren Sie einfach ActivatedRoute
like
import { ActivatedRoute } from '@angular/router'
und auf der ngOnInit
werden die Daten abgerufen
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
this.id = params['id'];
});
console.log(this.id);
}
sie können mehr in diesem Artikel lesen https://www.tektutorialshub.com/angular-passing-parameters-to-route/
Der dritte Ansatz ist die gebräuchlichste Methode, Daten zwischen Komponenten auszutauschen. Sie können den Artikel-Service hinzufügen, den Sie in der zugehörigen Komponente verwenden möchten.
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
}
Lösung mit aktiver Route (wenn Sie Objekt über Route übergeben möchten - verwenden Sie JSON.stringify/JSON.parse)
Objekt vor dem Senden vorbereiten:
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);
}
}
Empfangen Sie Ihr Objekt in der Zielkomponente:
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"]);
});
}
}
Eine super kluge Person (tmburnell), die ich nicht bin, schlägt vor, die Routendaten neu zu schreiben:
let route = this.router.config.find(r => r.path === '/path');
route.data = { entity: 'entity' };
this.router.navigateByUrl('/path');
Wie hier in den Kommentaren.
Ich hoffe, jemand findet das nützlich
In Angular 7.2.0 wurde eine neue Art der Datenübergabe beim Navigieren zwischen weitergeleiteten Komponenten eingeführt:
@Component({
template: `<a (click)="navigateWithState()">Go</a>`,
})
export class AppComponent {
constructor(public router: Router) {}
navigateWithState() {
this.router.navigateByUrl('/123', { state: { hello: 'world' } });
}
}
Oder:
@Component({
selector: 'my-app',
template: `
<a routerLink="/details" [state]="{ hello: 'world' }">Go</a>`,
})
export class AppComponent {}
Um den Status zu lesen, können Sie nach Abschluss der Navigation auf die Eigenschaft window.history.state
zugreifen:
export class PageComponent implements OnInit {
state$: Observable<object>;
constructor(public activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.state$ = this.activatedRoute.paramMap
.pipe(map(() => window.history.state))
}
}
Pass mit JSON
<a routerLink = "/link"
[queryParams] = "{parameterName: objectToPass| json }">
sample Link
</a>
Ich bin der andere Ansatz nicht gut für diese Frage. Ich denke, der beste Ansatz ist Query-Parameter durch Router
eckig, die 2 Wege haben:
Abfrageparameter direkt übergeben
Mit diesem Code können Sie über url
in Ihrem HTML-Code zu params
navigieren:
<a [routerLink]="['customer-service']" [queryParams]="{ serviceId: 99 }"></a>
Abfrageparameter von
Router
übergeben
Sie müssen den Router in Ihre constructor
einfügen:
constructor(private router:Router){
}
Verwenden Sie nun das wie:
goToPage(pageNum) {
this.router.navigate(['/product-list'], { queryParams: { serviceId: serviceId} });
}
Wenn Sie nun von Router
in einer anderen Component
lesen möchten, müssen Sie ActivatedRoute
wie folgt verwenden:
constructor(private activateRouter:ActivatedRouter){
}
und subscribe
dass:
ngOnInit() {
this.sub = this.route
.queryParams
.subscribe(params => {
// Defaults to 0 if no query param provided.
this.page = +params['serviceId'] || 0;
});
}
verwenden Sie einen gemeinsam genutzten Dienst, um Daten mit einem benutzerdefinierten Index zu speichern. Senden Sie dann diesen benutzerdefinierten Index mit queryParam. dieser Ansatz ist flexibler .
// 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']];
}
);
}
Wenn Sie Ihrem Benutzer keine Daten in der Abfragezeichenfolge der Navigations-URL zur Verfügung stellen möchten, können Sie die angeforderten Daten zwischen zwei verschiedenen Komponentenrouten mit localStorage übergeben.
Bevor Sie programmgesteuert navigieren
localStorage.setItem("myHiddenData", JSON.stringify(routeData));
this.router.navigate(["route"]);
Inside ngOnInit der zweiten Komponente
ngOnInit(): void {
this.dataFromRoute = localStorage.getItem("myHiddenData");
}
(Optional) Router Guard
Wenn Sie nicht möchten, dass der Benutzer ohne die Routendaten auf diese Seite zugreift, können Sie auch einen canActivate-Routenschutz erstellen, der dieser bestimmten Komponente zugeordnet ist und vor der Navigation prüft, ob die Daten im localStorage richtig eingestellt sind.
canActivate(): boolean {
if (localStorage.getItem("myHiddenData")) {
return true;
} else {
// redirect
this.router.navigate("Home");
return false;
}
Diese Problemumgehung ist etwas wortreich, kann jedoch nützlich sein, wenn der Benutzer nur mit den angeforderten Daten auf diese Seite zugreifen soll und der Benutzer diese übergebenen Daten nicht einfach ändern kann.
sag du hast
und Sie möchten Daten an component2.ts übergeben.
in component1.ts ist eine Variable mit Daten say
//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"}
});
}