Açısal yönlendirilmiş bileşenlere nasıl veri aktarırım?


268

Açısal 2 rotalarımdan birinde ( FirstComponent ) bir düğme var

first.component.html

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

Benim amaç elde etmektir:

Düğme koruması -> verileri korurken ve diğer bileşeni yönerge olarak kullanmadan başka bir bileşene yönlendirin.

Ben de bunu denedim ...

1. YAKLAŞIM

Aynı görünümde, kullanıcı etkileşimini temel alarak aynı verileri topluyorum.

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

Normalde tarafından İkinci Bileşene yönlendiririm

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

sonunda veriyi

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

oysa parametrelerle bağlantının tanımı

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

Bu yaklaşım ile ilgili sorun sanırım in-url karmaşık veri (örneğin property3 gibi bir nesne ) geçemez ;

2. YAKLAŞIM

Bir alternatif, FirstComponent'te direktif olarak SecondComponent'i dahil etmek olabilir.

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

Ancak ben bu bileşene yönlendirmek istiyorum , dahil değil!

3. YAKLAŞIM

Burada gördüğüm en uygun çözüm, Hizmet (ör. FirstComponentService) kullanmak için

  • depolamak FirstComponent içinde routeWithData ile (_firstComponentService.storeData ()) () verileri
  • almak içinde (_firstComponentService.retrieveData ()) verileri ngOnInit () içinde SecondComponent

Bu yaklaşım mükemmel bir şekilde uygulanabilir gibi görünse de, bunun hedefe ulaşmanın en kolay / en zarif yolu olup olmadığını merak ediyorum.

Genel olarak , özellikle mümkün olan daha az miktarda kodla , bileşenler arasında veri iletmek için başka potansiyel yaklaşımları kaçırıp kaçırmadığımı bilmek istiyorum



2
teşekkürler @Prashobh. Pass data using Query Parametersaradığım şey bu. senin bağlantı Günümü kurtardı.
Raj

Açısal 7.2, daha fazla ayrıntı stateiçin PR'ı kontrol ederek verileri rotalar arasında iletmek için yeni bir özelliğe sahiptir . Burada
AzizKapProg

@Prashobh Çok teşekkürler. Paylaştığınız bağlantı çok yararlı
vandu

Yanıtlar:


193

4.0.0 güncellemesi

Daha fazla ayrıntı için Açısal dokümanlar konusuna bakın https://angular.io/guide/router#fetch-data-before-navigating

orijinal

Bir servis kullanmak gidilecek yoldur. Rota parametrelerinde yalnızca tarayıcı URL çubuğuna yansıtılmasını istediğiniz verileri iletmeniz gerekir.

Ayrıca bkz. Https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

RC.4 ile birlikte gelen yönlendirici, 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();
  }
}

Ayrıca bkz. Plunker, https://github.com/angular/angular/issues/9757#issuecomment-229847781


4
Bu cevap Açısal 2.1.0 için hala geçerli mi?
smartmouse

9
RC.4 yönlendirici verileri yalnızca statik veriler içindir. Aynı rotaya her zaman aynı veri olması gereken farklı veriler gönderemez miyim?
aycanadal

1
Hayır, bu kullanım durumu için paylaşılan bir hizmet kullanın.
Günter Zöchbauer

8
Yine de Açısal 5'de şunları yapabilmelisiniz ... ngOnInit() { this.myVar = this.route.snapshot.data['some_data']; }
Roger

5
Angular v7.2'yi kullanabiliyorsanız, şimdi NavigationExtras- stackoverflow.com/a/54879389/1148107
mtpultz

67

Bence açısal 2'de açısal 1.x'te olduğu gibi $ rootScope türümüz yok . NgOnDestroy'da hizmete geçiş verilerini kullanırken açısal 2 paylaşılan hizmeti / sınıfı kullanabiliriz ve yönlendirmeden sonra ngOnInit işlevindeki verileri hizmetten alabiliriz :

Burada kahraman nesnesini paylaşmak için DataService kullanıyorum:

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

Nesneyi ilk sayfa bileşeninden geçir:

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

Nesneyi ikinci sayfa bileşeninden al:

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

İşte bir örnek: plunker


Bu güzel, ama Ng2 topluluğunda bu ne kadar yaygın? Dokümanlarda okuduğumu hatırlayamıyorum ...
Alfa Bravo

1
URL parametreleri veya diğer tarayıcı depolaması gibi diğer seçeneklerle karşılaştırıldığında bu bana daha iyi geliyor. Ben de böyle çalışmak için herhangi bir belge görmedim.
Utpal Kumar Das

2
Kullanıcı yeni bir sekme açıp ikinci bileşen yolunu kopyalayıp yapıştırdığında çalışır mı? Getirebilir miyim this.hero = this.dataService.hero? Değerleri alacak mıyım?

Bu gerçekten çok basit ve her Açısal geliştirici biliyor ama sorun bir kez hizmetlerde veri gevşek yenilemek. Kullanıcı her şeyi tekrar yapmak zorunda kalacaktır.
Santosh Kadam

@SantoshKadam soru "Verileri açısal yönlendirilmiş bileşenlere nasıl aktarırım?" bu nedenle ngOnDestroy ve ngOnInit işlevleriyle veri iletmenin bir yolu vardır ve her zaman basit olan en iyisidir. Kullanıcının yeniden yüklemeden sonra veri alması gerekiyorsa, verileri kalıcı bir depolama alanına kaydetmeli ve bu depolama biriminden tekrar okumalıdır.
Utpal Kumar Das

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

Açısal 6 veya diğer sürümlerde yapmanın en kolay yolu, umarım yolunuzu geçmek istediğiniz veri miktarı ile tanımlamaktır.

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

rota tanımımdan da görebileceğiniz gibi /:id, bileşene yönlendirmek istediğim veriye yönelticinin navigasyonuyla eklenmesini bekledim. Bu nedenle kodunuz

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

idbileşeni okumak için , sadece ActivatedRoute gibi ithal

import { ActivatedRoute } from '@angular/router'

ve ngOnInitburada verileri alırsınız

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

bu makalede daha fazlasını okuyabilirsiniz https://www.tektutorialshub.com/angular-passing-parameters-to-route/


12
karmaşık bir nesne göndermek istersem ne olur? rotalarımı
sürdürülemez

@cmxl Paylaşılan bir hizmet kullanın.
Stanislasdrg Monica'ya

Tam aradığım şey. Teşekkürler!
Akhil

21

Açısal 7.2.0, yönlendirilen bileşenler arasında gezinirken verileri aktarmanın yeni yolunu tanıttı:

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

Veya:

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

Durumu okumak için window.history.state, gezinme işlemi bittikten sonra mülke erişebilirsiniz :

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

  constructor(public activatedRoute: ActivatedRoute) {}

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

4
benim için çalışmaz, ilettiğim nesneyi döndürmek yerine bir window.history.stateşey döndürür {navigationId: 2}.
Louis

@ Hangi açısal sürümü kullanıyorsunuz?
Washington Soares Braga

Açılı sürüm 8.1.0 kullanıyorum
Louis

Louis ile aynı şeyi görüyorum, ondan daha düşük bir versiyona sahip ama yine de bu özelliğe sahip olması gereken kadar yüksek.
WindowsWeenie

döndürülen nesnenin bir parçası olarak, navigationIdbir değer eklenir. Hiçbir veri eklenmezse, yalnızca veri navigationIdgösterilir. Aktarılan verilere bakın, geri dönün veya uygulamanızı yenileyin ve verileri rotaya ekleyen ve bir sonraki rotaya (örn. Düğme tıklaması) giden işlemi yeniden tetikleyin. Bu, verilerinizi nesneye ekler.
Alf Moh

12

Ben olmayan bazı süper akıllı kişiler (tmburnell) rota verilerinin yeniden yazılmasını önerir:

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

Burada yorumlarda görüldüğü gibi .

Umarım birisi bunu faydalı bulur


7
sadece bu konuda öğrendim ve bazı stackoverflow noktalarına ihtiyacım var gibi hissediyorum :)
Tim.Burnell

11

Ben diğer yaklaşım bu konuda iyi değil. Ben en iyi yaklaşım 2 yollu açısal tarafından Query-ParameterRouter olduğunu şey:

Sorgu parametresini doğrudan iletme

Bu kod ile gidebilirsiniz urltarafından paramshtml kodu:

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

Sorgu parametresini şu şekilde geçirme: Router

Yönlendiriciyi istediğiniz constructorgibi enjekte etmeniz gerekir :

constructor(private router:Router){

}

Şimdi bunun gibi kullanın:

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

Şimdi Routerbaşka birinden okumak Componentistiyorsanız, aşağıdaki ActivatedRoutegibi kullanmanız gerekir :

constructor(private activateRouter:ActivatedRouter){

}

ve subscribebu:

  ngOnInit() {
    this.sub = this.route
      .queryParams
      .subscribe(params => {
        // Defaults to 0 if no query param provided.
        this.page = +params['serviceId'] || 0;
      });
  }

this.router.navigate (['/ ürün listesi'], {queryParams: {serviceId: serviceId}}); this.router.navigate (['/ ürün listesi'], {queryParams: {serviceId}}) ile değiştirilebilir;
Ramakant Singh

10

2019 ve buradaki cevapların çoğu, ne yapmak istediğinize bağlı olarak işe yarayacak. URL'de görünmeyen bazı dahili durumlardan geçmek istiyorsanız (params, sorgu) state7.2'den beri kullanabilirsiniz ( bugün öğrendiğim gibi :)).

Blogdan (kredi Tomasz Kula) - rotaya gidin ....

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

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

Ve bunu hedef bileşende almak için:

constructor(public activatedRoute: ActivatedRoute) {}

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

Geç, ama umarım bu yeni Angular'a sahip birine yardım eder.


6

ActiveRoute ile çözüm (nesneyi rotaya göre geçmek istiyorsanız - JSON.stringfy / JSON.parse kullanın):

Göndermeden önce nesneyi hazırlayın:

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

}

Hedef bileşende nesnenizi alın:

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

}

1
Bu işe yarar, ancak URL’deki tüm verileri göstermek istemezsem ne olur?
mpro

Hedef bileşende şifreledikten sonra parametrelere koyduğunuz verileri şifreleyebilirsiniz.
akrep

Ben ettik hizmeti oluşturulan veri paylaşımı için.
mpro

Bu ne super.ngOnInit();için?
Andrea Gherardi

5

3. yaklaşım, bileşenler arasında veri paylaşmanın en yaygın yoludur. ilgili bileşende kullanmak istediğiniz öğe hizmetini enjekte edebilirsiniz.

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
}

3
Güzergah değiştirilirken servis başlatılır. Böylece verileri kaybedersiniz
Jimmy Kane

1
@JimmyKane Özellikle sayfa yenilendiğinde bahsediyorsunuz, ancak yenilenmiyorsa bellek yine de bir servise kaydedilir. Yüklemeyi birçok kez kaydedeceği için bu varsayılan davranış olmalıdır.
Aaron Rabinowitz

1
@AaronRabinowitz doğru. Karışıklık için özür dilerim. Ve aşağı oylama için özür dilerim. Keşke şimdi geri alabilsem. Çok geç. Açısal 2 için yeni ve yaklaşımınızı denerken benim sorunum birçok bileşen için sağlanan hizmet vardı ve app modülü aracılığıyla sağlanan değildi.
Jimmy Kane

3

JSON kullanarak geçiş

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

7
Parametrenin alıcı bileşende de nasıl kullanıldığını gösterebiliyorsanız, bu daha iyi bir yanıt olacaktır - tüm rotayı. Birisi bir parametrenin nasıl iletileceğini bilmiyorsa, bu parametrenin alıcı bileşende nasıl kullanılacağını da bilemez. :)
Alfa Bravo

Bunun bir dezavantajı, sorgu dizesinde boyut sınırlaması olması ve bazen adres çubuğunda nesne özelliklerinin görünmesini istememenizdir.
CM

3

özel bir dizine sahip verileri depolamak için paylaşılan bir hizmet kullanın. ardından bu özel dizini queryParam ile gönderin. bu yaklaşım daha esnektir .

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

söyle var

  1. component1.ts
  2. component1.html

ve veri geçmek isteyen component2.ts .

  • bileşen1.ts içinde veri

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

Yönlendirilen bileşenler arasında veri paylaşmak için BehaviorSubject kullanabilirsiniz. Bir BehaviorSubject bir değer tutar. Abone olunca değeri hemen yayar. Bir Konunun değeri yoktur.

Serviste.

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

Bileşende bu BehaviorSubject öğesine abone olabilirsiniz.

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

Not: Konu burada çalışmaz, Yalnızca Davranış Konusunu kullanmanız gerekir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.