Angular 라우팅 구성 요소에 데이터를 전달하려면 어떻게합니까?


268

내 Angular 2 경로 템플릿 중 하나 ( FirstComponent )에 버튼이 있습니다.

first.component.html

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

목표 는 달성하는 것입니다.

버튼 클릭-> 다른 구성 요소를 지시문으로 사용하지 않고 데이터를 유지하면서 다른 구성 요소로 라우팅합니다.

이것은 내가 시도한 것입니다 ...

첫 번째 접근법

같은보기에서 나는 사용자 상호 작용을 기반으로 동일한 데이터를 수집 저장합니다.

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

일반적으로 다음 으로

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

결국 데이터를 전달

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

반면 매개 변수가있는 링크의 정의는

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

이 접근법의 문제는 복잡한 데이터 (예 : property3와 같은 객체 )를 URL로 전달할 수 없다는 것입니다 .

2 차 접근법

대안은 FirstComponent 에서 SecondComponent 를 지시문 으로 포함하는 것 입니다.

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

그러나 해당 구성 요소 로 라우팅 하고 싶지 는 않습니다.

3 차 접근법

내가 볼 수있는 가장 실용적인 해결책은 서비스 (예 : FirstComponentService)를 사용하여

  • FirstComponent의 routeWithData ()에 데이터 (_firstComponentService.storeData ())를 저장 하십시오.
  • 검색 의 (_firstComponentService.retrieveData ()) 데이터를 ngOnInit ()을SecondComponent

이 접근법은 완벽하게 실행 가능한 것처럼 보이지만 이것이 목표를 달성하는 가장 쉽고 우아한 방법인지 궁금합니다.

일반적으로 구성 요소간에 데이터를 전달하는 다른 잠재적 인 접근법 이 누락되었는지 , 특히 코드의 양이 적을 지 알고 싶습니다.


6
경로를 통해 데이터를 공유하는 3 가지 간단한 방법 -angulartutorial.net/2017/12/…
Prashobh

2
@Prashobh에게 감사합니다. Pass data using Query Parameters내가 찾던 것입니다. 당신의 링크는 내 하루를 저장했습니다.
Raj

Angular 7.2에는 이제 PRstate 확인을 사용하여 경로간에 데이터를 전달하는 새로운 기능이 추가되었습니다. 여기에 유용한 정보가 있습니다
AzizKapProg

@Prashobh 감사합니다. 당신이 공유 한 링크는 매우 유용합니다
vandu

답변:


193

4.0.0 업데이트

자세한 내용은 각도 문서를 참조하십시오 https://angular.io/guide/router#fetch-data-before-navigating

실물

서비스를 사용하는 것이 좋습니다. 경로 매개 변수에서는 브라우저 URL 표시 줄에 반영하려는 데이터 만 전달해야합니다.

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

RC.4와 함께 제공된 라우터는 다시 소개합니다 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();
  }
}

https://github.com/angular/angular/issues/9757#issuecomment-229847781 에서 Plunker를 참조하십시오.


4
이 답변이 여전히 Angular 2.1.0에 유효합니까?
smartmouse

9
RC.4 라우터 데이터는 정적 데이터 전용입니다. 동일한 경로로 다른 데이터를 보낼 수는 없습니다. 항상 동일한 데이터 여야합니다.
aycanadal

1
아니요,이 사용 사례에는 공유 서비스를 사용하십시오.
Günter Zöchbauer

8
각도 5에서, 어쨌든, 당신은 할 수 있어야 할 ... ngOnInit() { this.myVar = this.route.snapshot.data['some_data']; }
로저

5
Angular v7.2를 사용할 수 있다면 라우터에서 상태를 전달할 수 있습니다. NavigationExtras- stackoverflow.com
a

67

우리는 각도 1.x에서와 같이 각도 2에 $ rootScope 종류 가 없기 때문에 생각합니다 . ngOnDestroy 에서 데이터를 서비스로 전달 하는 동안 ngOnInit 함수 에서 서비스에서 데이터를 가져 오는 동안 angular 2 공유 서비스 / 클래스를 사용할 수 있습니다 .

여기서는 DataService를 사용하여 영웅 객체를 공유하고 있습니다.

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

첫 페이지 컴포넌트에서 오브젝트를 전달하십시오.

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

두 번째 페이지 구성 요소에서 객체를 가져옵니다.

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

다음은 예입니다 : plunker


이것은 아름답지만 Ng2 커뮤니티에서 얼마나 일반적입니까? 문서에서 읽은 것을 기억할 수 없습니다 ...
Alfa Bravo

1
URL 매개 변수 또는 다른 브라우저 저장소와 같은 다른 옵션과 비교하면 나에게 더 나은 것 같습니다. 나는 또한 이와 같이 작동하는 문서를 보지 못했습니다.
Utpal Kumar Das

2
사용자가 새 탭을 열고 두 번째 구성 요소 경로를 복사하여 붙여 넣을 때 작동합니까? 가져올 수 this.hero = this.dataService.hero있습니까? 값을 얻을 수 있습니까?

이것은 실제로 매우 간단하며 모든 Angular 개발자는 알고 있지만 서비스에서 느슨한 데이터를 새로 고치면 문제가 발생합니다. 사용자는 모든 작업을 다시 수행해야합니다.
Santosh Kadam 2016 년

@SantoshKadam 문제는 "어떻게 Angular 라우팅 된 컴포넌트에 데이터를 전달 하는가?"입니다. 따라서 ngOnDestroy 및 ngOnInit 함수로 데이터를 전달하는 것이 방법이며 항상 간단합니다. 사용자가 다시로드 한 후 데이터를 가져와야하는 경우 데이터를 영구 저장소에 저장하고 해당 저장소에서 다시 읽어야합니다.
Utpal Kumar Das

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

각도 6 또는 다른 버전에서 가장 쉬운 방법은 전달하려는 데이터 양으로 경로를 정의하는 것입니다.

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

내 경로 정의에서 볼 수 있듯이 /:id라우터 탐색을 통해 구성 요소에 전달하려는 데이터에 스탠드를 추가했습니다 . 따라서 코드는 다음과 같습니다

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

id구성 요소 를 읽으려면 다음 ActivatedRoute 과 같이 가져 오십시오.

import { ActivatedRoute } from '@angular/router'

그리고 ngOnInit당신이 데이터를 검색하는 곳

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

이 기사에서 더 많은 것을 읽을 수 있습니다 https://www.tektutorialshub.com/angular-passing-parameters-to-route/


12
복잡한 개체를 보내려면 어떻게합니까? 유지 관리 할 수없는 말도 안되는 경로를
부풀리고

@cmxl 그런 다음 공유 서비스를 사용하십시오.
Stanislasdrg Reinstate Monica

정확히 내가 찾던 것. 감사!
Akhil

21

Angular 7.2.0에서는 라우팅 된 구성 요소 사이를 탐색 할 때 데이터를 전달하는 새로운 방법을 도입했습니다.

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

또는:

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

상태를 읽으려면 window.history.state탐색이 완료된 후 속성에 액세스 할 수 있습니다 .

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

  constructor(public activatedRoute: ActivatedRoute) {}

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

4
나를 위해 작동하지 않고 전달 된 객체를 반환하는 대신 window.history.state같은 것을 {navigationId: 2}반환합니다.
Louis

@Louis 어떤 Angular 버전을 사용하고 있습니까?
워싱턴 Soares Braga

각도 버전 8.1.0을 사용하고 있습니다.
Louis

나는 루이스와 같은 것을 보았습니다. 그의 버전보다 낮은 버전이지만 여전히 그 기능을 가질 정도로 높습니다.
WindowsWeenie

반환 된 객체의 일부로 navigationId값이 추가됩니다. 데이터가 추가되지 않으면가 navigationId표시됩니다. 전달 된 데이터를 확인하고, 돌아가거나 앱을 새로 고친 후 데이터를 경로에 추가하고 다음 경로 (예 : 버튼 클릭)로 이동하는 동작을 다시 트리거하십시오. 그러면 데이터가 객체에 추가됩니다.
Alf Moh

12

내가 아닌 슈퍼 똑똑한 사람 (tmburnell)은 경로 데이터를 다시 쓰도록 제안합니다.

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

의견에서 여기 에서 볼 수 있듯이 .

누군가가 이것을 유용하게 사용하기를 바랍니다.


7
단지 : 이것에 대해 발견하고 내가 어떤 유래 포인트가 필요 같은 느낌
Tim.Burnell

11

나는 이것이 다른 방법 으로이 문제에 좋지 않다. 가장 좋은 방법은 각도 별로 쿼리 매개 변수입니다Router .

쿼리 매개 변수를 직접 전달

이 코드를 사용하면 탐색 할 수 있습니다 url하여 paramsHTML 코드에서 :

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

다음에 의해 쿼리 매개 변수 전달 Router

당신은 당신의 constructor마음에 라우터를 주입해야합니다 :

constructor(private router:Router){

}

이제 다음과 같이 사용하십시오.

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

이제 Router다른 곳 에서 읽으려면 다음과 같이 Component사용해야합니다 ActivatedRoute.

constructor(private activateRouter:ActivatedRouter){

}

그리고 subscribe그것은 :

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

this.router.navigate ([ '/ product-list'], {queryParams : {serviceId : serviceId}}); this.router.navigate ([ '/ product-list'], {queryParams : {serviceId}});로 대체 될 수 있습니다.
라마 칸트 싱

10

2019 년이며 여기에 원하는 답변에 따라 많은 답변이 작동합니다. URL (매개 변수, 쿼리)에 보이지 않는 내부 상태를 전달하려면 state7.2 오늘 부터 사용할 수 있습니다 ( 오늘 방금 배운 것처럼 :)).

블로그 (신용 Tomasz Kula)-경로로 이동하십시오 ....

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

... HTML 템플릿에서 : <a routerLink="/details" [state]="{ hello: 'world' }">Go</a>

대상 구성 요소에서 가져옵니다.

constructor(public activatedRoute: ActivatedRoute) {}

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

늦었지만 이것이 최근 Angular를 가진 사람에게 도움이되기를 바랍니다.


6

ActiveRoute 솔루션 (경로로 객체를 전달하려면 JSON.stringfy / JSON.parse를 사용하십시오) :

보내기 전에 물건을 준비하십시오 :

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

}

대상 컴포넌트에서 오브젝트를 수신하십시오.

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
작동하지만 URL의 모든 데이터를 공개하지 않으려면 어떻게해야합니까?
mpro

대상 구성 요소에서 암호화 한 후 매개 변수에 넣은 데이터를 암호화 할 수 있습니다.
전갈

나는 한 서비스 생성 된 데이터 공유를.
mpro

그게 뭐야 super.ngOnInit();?
Andrea Gherardi

5

세 번째 접근 방식은 구성 요소간에 데이터를 공유하는 가장 일반적인 방법입니다. 관련 컴포넌트에서 사용하려는 아이템 서비스를 주입 할 수 있습니다.

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
경로를 전환 할 때 서비스가 인스턴스화됩니다. 데이터
Jimmy Kane

1
@JimmyKane 페이지를 새로 고칠 때 특별히 말하지만 새로 고치지 않으면 메모리는 여전히 서비스에 저장됩니다. 로딩을 여러 번 저장하기 때문에 이것이 기본 동작이어야합니다.
Aaron Rabinowitz '

1
@AaronRabinowitz 맞습니다. 혼란을 드려 죄송합니다. 그리고 다운 투표에 대해 죄송합니다. 지금 취소 할 수 있으면 좋겠습니다. 너무 늦었 어 앵귤러 2에 익숙하지 않았고 접근 방식을 시도 할 때의 문제는 서비스가 많은 구성 요소에 제공되었지만 앱 모듈을 통해 제공되지 않았다는 것입니다.
지미 케인

3

JSON을 사용하여 전달

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

7
수신 구성 요소에서 매개 변수가 소비되는 방식 (전체 경로)을 보여줄 수 있다면 더 나은 대답이 될 것입니다. 누군가 매개 변수를 전달하는 방법을 모른다면 수신 구성 요소에서이 매개 변수를 사용하는 방법도 알지 못합니다. :)
Alfa Bravo

이것의 단점은 쿼리 문자열에 크기 제한이 있으며 때로는 주소 표시 줄에 객체 속성을 표시하지 않으려는 것입니다.
CM

3

공유 서비스를 사용하여 사용자 정의 색인으로 데이터를 저장하십시오. 그런 다음 queryParam을 사용하여 해당 사용자 정의 색인을 보내십시오. 이 방법은보다 유연 합니다.

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

당신이 있다고 말해

  1. component1.ts
  2. component1.html

데이터를 component2.ts 로 전달하려고합니다 .

  • component1.ts에서 데이터가있는 변수입니다

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

라우팅 된 구성 요소간에 데이터를 공유하기 위해 BehaviorSubject를 사용할 수 있습니다. BehaviorSubject에는 하나의 값이 있습니다. 구독하면 즉시 값을 내 보냅니다. 주제는 가치를 보유하지 않습니다.

서비스 중.

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

컴포넌트에서이 BehaviorSubject를 구독 할 수 있습니다.

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

참고 : 여기서는 주제가 작동하지 않으므로 행동 주제 만 사용해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.