wake-up-neo.net

Wie kann ich Daten an Angular-Komponenten weiterleiten?

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 

  • speichern die Daten (_firstComponentService.storeData ()) auf routeWithData () in FirstComponent
  • Abrufen der Daten (_firstComponentService.retrieveData ()) in ngOnInit () in SecondComponent

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

145
dragonmnl

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

111

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

47
Utpal Kumar Das
<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
}
5
ahankendi

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"]);
      });
  }

}
3
scorpion

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

3
terary

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>
2

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;
      });
  }
1

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']];
        }
    );
}
0
Amin Adel

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

  1. component1.ts
  2. component1.html

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"}
       });
      }
    
0
Nelson Bwogora