Bagaimana cara meneruskan data ke komponen yang diarahkan ke Sudut?

268

Di salah satu template Angular 2 route saya ( FirstComponent ) saya memiliki tombol

first.component.html

<div class="button" click="routeWithData()">Pass data and route</div>

Tujuan saya adalah mencapai:

Klik tombol -> rute ke komponen lain sambil menyimpan data dan tanpa menggunakan komponen lain sebagai arahan.

Ini yang saya coba ...

PENDEKATAN 1

Dalam tampilan yang sama saya menyimpan pengumpulan data yang sama berdasarkan interaksi pengguna.

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

Biasanya saya akan rute ke SecondComponent oleh

 this._router.navigate(['SecondComponent']);

akhirnya melewati data dengan

 this._router.navigate(['SecondComponent', {p1: this.property1, p2: property2 }]);

sedangkan definisi tautan dengan parameter adalah

@RouteConfig([
      // ...
      { path: '/SecondComponent/:p1:p2', name: 'SecondComponent', component: SecondComponent} 
)]

Masalah dengan pendekatan ini adalah saya kira saya tidak bisa melewatkan data yang kompleks (misalnya objek seperti property3) di-url;

PENDEKATAN 2ND

Alternatif akan menyertakan SecondComponent sebagai arahan dalam FirstComponent.

  <SecondComponent [p3]="property3"></SecondComponent>

Namun saya ingin merutekan ke komponen itu, tidak termasuk!

PENDEKATAN 3RD

Solusi paling layak yang saya lihat di sini adalah menggunakan Layanan (mis. FirstComponentService) untuk

  • menyimpan data (_firstComponentService.storeData ()) pada routeWithData () di FirstComponent
  • mengambil data (_firstComponentService.retrieveData ()) di ngOnInit () di SecondComponent

Sementara pendekatan ini tampaknya sangat layak, saya bertanya-tanya apakah ini adalah cara termudah / paling elegan untuk mencapai tujuan.

Secara umum saya ingin tahu apakah saya kehilangan pendekatan potensial lain untuk meneruskan data antar komponen, terutama dengan jumlah kode yang lebih sedikit

dragonmnl
sumber
6
3 cara sederhana untuk berbagi data melalui rute - angulartutorial.net/2017/12/…
Prashobh
2
terima kasih @ Prashobh. Pass data using Query Parametersadalah apa yang saya cari. tautan Anda menyelamatkan hari saya.
Raj
Angular 7.2 sekarang memiliki fitur baru untuk meneruskan data antar rute menggunakan statecek PR untuk detail lebih lanjut. Beberapa informasi berguna di sini
AzizKapProg
@ Prashobh Terima kasih banyak. Tautan yang telah Anda bagikan sangat bermanfaat
vandu

Jawaban:

193

perbarui 4.0.0

Lihat dokumen Angular untuk detail lebih lanjut https://angular.io/guide/router#fetch-data-before-navigating

asli

Menggunakan layanan adalah cara untuk pergi. Dalam params rute, Anda hanya harus meneruskan data yang ingin Anda tampilkan di bilah URL browser.

Lihat juga https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

Router yang dikirim dengan RC.4 memperkenalkan kembali 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();
  }
}

Lihat juga Plunker di https://github.com/angular/angular/issues/9757#issuecomment-229847781

Günter Zöchbauer
sumber
4
Apakah jawaban ini masih berlaku untuk Angular 2.1.0?
smartmouse
9
Data router RC.4 hanya untuk data statis. Anda tidak dapat mengirim data berbeda ke rute yang sama selalu harus data yang sama apakah saya salah?
aycanadal
1
Tidak, gunakan layanan bersama untuk kasus penggunaan ini.
Günter Zöchbauer
8
Di Angular 5, bagaimanapun, Anda harus bisa ... ngOnInit() { this.myVar = this.route.snapshot.data['some_data']; }
Roger
5
Jika Anda dapat menggunakan Angular v7.2, ini memungkinkan untuk melewati status sekarang di router menggunakan NavigationExtras- stackoverflow.com/a/54879389/1148107
mtpultz
67

Saya pikir karena kita tidak memiliki $ rootScope semacam itu di sudut 2 seperti di sudut 1.x. Kita dapat menggunakan layanan / kelas sudut 2 saat dalam ngOnDestroy meneruskan data ke layanan dan setelah routing mengambil data dari layanan dalam fungsi ngOnInit :

Di sini saya menggunakan DataService untuk berbagi objek pahlawan:

import { Hero } from './hero';
export class DataService {
  public hero: Hero;
}

Lulus objek dari komponen halaman pertama:

 ngOnDestroy() {
    this.dataService.hero = this.hero; 
 }

Ambil objek dari komponen halaman kedua:

 ngOnInit() {
    this.hero = this.dataService.hero; 
 }

Berikut ini contohnya: plunker

Utpal Kumar Das
sumber
Ini indah, tetapi seberapa umum dalam komunitas Ng2 ini? Saya tidak ingat membacanya di dokumen ...
Alfa Bravo
1
Dibandingkan dengan opsi lain seperti parameter url atau penyimpanan browser lain, menurut saya ini lebih baik. Saya juga tidak melihat dalam dokumentasi apa pun untuk bekerja seperti ini.
Utpal Kumar Das
2
Apakah itu berfungsi ketika pengguna membuka tab baru dan menyalin tempel rute komponen kedua? Bisakah saya mengambilnya this.hero = this.dataService.hero? Apakah saya akan mendapatkan nilainya?
Ini memang sangat sederhana dan setiap pengembang Angular tahu tetapi masalahnya adalah setelah Anda menyegarkan kembali data yang hilang di layanan. Pengguna harus melakukan semua hal lagi.
Santosh Kadam
@SantoshKadam pertanyaannya adalah "Bagaimana cara saya meneruskan data ke komponen yang diarahkan ke Angular?" jadi melewatkan data dengan fungsi ngOnDestroy dan ngOnInit adalah caranya, dan selalu sederhana adalah yang terbaik. Jika pengguna perlu mendapatkan data setelah memuat ulang maka perlu menyimpan data dalam penyimpanan permanen dan membaca lagi dari penyimpanan itu.
Utpal Kumar Das
28
<div class="button" click="routeWithData()">Pass data and route</div>

nah cara termudah untuk melakukannya dalam angular 6 atau versi lain yang saya harap adalah dengan mendefinisikan path Anda dengan jumlah data yang ingin Anda lewati

{path: 'detailView/:id', component: DetailedViewComponent}

seperti yang dapat Anda lihat dari definisi rute saya, saya telah menambahkan status /:idke data yang ingin saya sampaikan ke komponen melalui navigasi router. Karenanya kode Anda akan terlihat seperti

<a class="btn btn-white-view" [routerLink]="[ '/detailView',list.id]">view</a>

untuk membaca idpada komponen, impor saja ActivatedRoute like

import { ActivatedRoute } from '@angular/router'

dan di ngOnInittempat Anda mengambil data

ngOnInit() {
       this.sub = this.route.params.subscribe(params => {
        this.id = params['id'];
        });
        console.log(this.id);
      }

Anda dapat membaca lebih lanjut di artikel ini https://www.tektutorialshub.com/angular-passing-parameters-to-route/

Daniel Charles Mwangila
sumber
12
bagaimana jika saya ingin mengirim objek yang kompleks? saya tidak ingin mengasapi rute saya ke omong kosong yang tidak dapat dipelihara :(
cmxl
@cmxl Gunakan layanan bersama lalu.
Stanislasdrg Reinstate Monica
Persis apa yang saya cari. Terima kasih!
Akhil
21

7.2.0 sudut memperkenalkan cara baru melewatkan data saat menavigasi antara komponen yang diarahkan:

@Component({
  template: `<a (click)="navigateWithState()">Go</a>`,
})
export class AppComponent  {
  constructor(public router: Router) {}
  navigateWithState() {
    this.router.navigateByUrl('/123', { state: { hello: 'world' } });
  }
}

Atau:

@Component({
  selector: 'my-app',
  template: `
  <a routerLink="/details" [state]="{ hello: 'world' }">Go</a>`,
})
export class AppComponent  {}

Untuk membaca keadaan, Anda dapat mengakses window.history.stateproperti setelah navigasi selesai:

export class PageComponent implements OnInit {
  state$: Observable<object>;

  constructor(public activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    this.state$ = this.activatedRoute.paramMap
      .pipe(map(() => window.history.state))
  }
}
Washington Soares Braga
sumber
4
tidak berfungsi untuk saya, window.history.statemengembalikan sesuatu seperti {navigationId: 2}bukannya mengembalikan objek yang saya lewati.
Louis
@ Louis Apakah versi Angular yang Anda gunakan?
Washington Soares Braga
Saya menggunakan versi sudut 8.1.0
Louis
Saya melihat hal yang sama dengan Louis, dengan versi yang lebih rendah dari versi itu tetapi masih cukup tinggi sehingga seharusnya memiliki fitur itu.
WindowsWeenie
sebagai bagian dari objek yang dikembalikan, navigationIddengan nilai yang ditambahkan. Jika tidak ada data yang ditambahkan, hanya yang navigationIdakan ditampilkan. Lihatlah data yang lewat, kembali atau segarkan aplikasi Anda dan picu kembali tindakan yang menambahkan data ke rute dan bernavigasi ke rute berikutnya (mis. Klik tombol). Ini kemudian akan menambahkan data Anda ke objek.
Alf Moh
12

Beberapa orang super pintar (tmburnell) yang bukan saya menyarankan untuk menulis ulang data rute:

let route = this.router.config.find(r => r.path === '/path');
route.data = { entity: 'entity' };
this.router.navigateByUrl('/path');

Seperti yang terlihat di sini di komentar.

Saya harap seseorang akan menemukan ini berguna

terarium
sumber
7
baru tahu tentang ini dan saya merasa saya perlu beberapa poin stackoverflow :)
Tim.Burnell
11

Saya ini pendekatan lain tidak baik untuk masalah ini. Saya kira pendekatan terbaik adalah Query-Parameter oleh Routerangular yang memiliki 2 cara:

Melewati parameter kueri secara langsung

Dengan kode ini Anda dapat menavigasi ke urloleh paramskode html Anda:

<a [routerLink]="['customer-service']" [queryParams]="{ serviceId: 99 }"></a>

Melewati parameter kueri dengan Router

Anda harus menyuntikkan router ke dalam constructorsuka Anda :

constructor(private router:Router){

}

Sekarang gunakan itu seperti:

goToPage(pageNum) {
    this.router.navigate(['/product-list'], { queryParams: { serviceId: serviceId} });
}

Sekarang jika Anda ingin membaca dari yang Routerlain ComponentAnda harus menggunakan ActivatedRoutelike:

constructor(private activateRouter:ActivatedRouter){

}

dan subscribeitu:

  ngOnInit() {
    this.sub = this.route
      .queryParams
      .subscribe(params => {
        // Defaults to 0 if no query param provided.
        this.page = +params['serviceId'] || 0;
      });
  }
AmirReza-Farahlagha
sumber
this.router.navigate (['/ daftar produk'], {queryParams: {serviceId: serviceId}}); dapat diganti dengan this.router.navigate (['/ daftar produk'], {queryParams: {serviceId}});
Ramakant Singh
10

Ini 2019 dan banyak jawaban di sini akan berhasil, tergantung pada apa yang ingin Anda lakukan. Jika Anda ingin melewati beberapa keadaan internal yang tidak terlihat di URL (params, query) Anda dapat menggunakan statesejak 7.2 (seperti yang saya pelajari hari ini :)).

Dari blog (kredit Tomasz Kula) - Anda menavigasi ke rute ....

... dari ts: this.router.navigateByUrl('/details', { state: { hello: 'world' } });

... dari templat HTML: <a routerLink="/details" [state]="{ hello: 'world' }">Go</a>

Dan untuk mengambilnya di komponen target:

constructor(public activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    this.state$ = this.activatedRoute.paramMap
      .pipe(map(() => window.history.state))
  }

Terlambat, tapi harap ini membantu seseorang dengan Angular baru-baru ini.

PeS
sumber
6

Solusi dengan ActiveRoute (jika Anda ingin melewati objek dengan rute - gunakan JSON.stringfy / JSON.parse):

Siapkan objek sebelum mengirim:

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

}

Terima objek Anda di komponen tujuan:

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

}
kalajengking
sumber
1
Itu berfungsi, tetapi bagaimana jika saya tidak ingin memaparkan semua data di URL?
mpro
Anda dapat mengenkripsi data yang dimasukkan ke params, setelah itu mengenkripsi di komponen target.
kalajengking
Saya telah membuat layanan untuk berbagi data.
mpro
Untuk apa itu super.ngOnInit();?
Andrea Gherardi
5

Pendekatan ke-3 adalah cara paling umum untuk berbagi data antar komponen. Anda dapat menyuntikkan layanan item yang ingin Anda gunakan dalam komponen terkait.

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
}
ahankendi
sumber
3
Layanan akan dipakai saat berganti rute. Jadi, Anda kehilangan data
Jimmy Kane
1
@ JimmyKane Anda berbicara tentang secara spesifik ketika halaman diperbarui tetapi jika tidak diperbarui maka memori masih disimpan dalam layanan. Ini harus menjadi perilaku default karena ini akan menghemat pemuatan berkali-kali.
Aaron Rabinowitz
1
@ HarunRabinowitz benar. Maaf bila membingungkan. Dan maaf atas suara yang turun. Seandainya aku bisa membatalkannya sekarang. Sangat terlambat. Adalah hal baru untuk sudut 2 dan masalah saya dengan mencoba pendekatan Anda adalah bahwa saya memiliki layanan yang disediakan untuk banyak komponen dan tidak disediakan melalui modul aplikasi.
Jimmy Kane
3

Lewati menggunakan JSON

  <a routerLink = "/link"
   [queryParams] = "{parameterName: objectToPass| json }">
         sample Link                   
  </a>

sumber
7
Ini akan menjadi jawaban yang lebih baik jika Anda dapat menunjukkan bagaimana parameter dikonsumsi dalam komponen penerima juga - seluruh rute yang dibutuhkan. Berarti jika seseorang tidak tahu cara melewatkan parameter, ia juga tidak akan tahu cara menggunakan parameter ini di komponen penerima. :)
Alfa Bravo
Kerugian dari ini adalah ada batasan ukuran untuk querystring dan kadang-kadang Anda tidak ingin properti objek terlihat di bilah alamat.
CM
3

menggunakan layanan bersama untuk menyimpan data dengan indeks khusus. lalu kirim indeks khusus itu dengan queryParam. pendekatan ini lebih fleksibel .

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

katakan kamu punya

  1. component1.ts
  2. component1.html

dan Anda ingin meneruskan data ke component2.ts .

  • di component1.ts adalah variabel dengan data 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"}
       });
      }
Nelson Bwogora
sumber
0

Anda dapat menggunakan BehaviorSubject untuk berbagi data antar komponen yang dirutekan. BehaviorSubject memegang satu nilai. Saat berlangganan, ia akan segera mengeluarkan nilai. Subjek tidak memiliki nilai.

Dalam layanan.

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

Dalam komponen Anda dapat berlangganan BehaviorSubject ini.

this.reportService.reportFilter.subscribe(f => {
      if (f) {
        this.reportFilter = f;
      }
    });

Catatan: Subjek tidak akan berfungsi di sini, Hanya perlu menggunakan Subjek Perilaku.

sushil suthar
sumber