programing

Angular Routed 컴포넌트에 데이터를 전달하려면 어떻게 해야 합니까?

bestprogram 2023. 3. 13. 21:09

Angular Routed 컴포넌트에 데이터를 전달하려면 어떻게 해야 합니까?

Angular 2 루트의 템플릿(First Component) 중 하나에 버튼이 있습니다.

first.component.displaces

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

목표는 다음과 같습니다.

다른 컴포넌트를 명령어로 사용하지 않고 데이터를 유지하면서 버튼을 클릭하여 다른 컴포넌트로 이동합니다.

이게 내가 시도했던...

첫 번째 접근법

같은 뷰에, 유저의 조작에 근거해 같은 데이터를 수집해 보존하고 있습니다.

첫 번째 컴포넌트.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
    }
}

보통 다음 방법으로 Second Component에 라우팅합니다.

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

결국 데이터 전달

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

반면 파라미터가 있는 링크의 정의는 다음과 같습니다.

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

이 접근방식의 문제는 복잡한 데이터(property3와 같은 객체)를 url로 전달할 없다는 것입니다.

두 번째 접근법

다른 방법으로는 First Component에 지시문으로 Second Component를 포함할 수 있습니다.

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

단, 그 컴포넌트를 포함하지 않고 그 컴포넌트로 라우팅하고 싶습니다.

세 번째 접근법

여기서 볼 수 있는 가장 실용적인 솔루션은 서비스(: First Component Service)를 사용하여

  • 루트상의 데이터(_first Component Service.storeData())를 저장합니다.First Component의 WithData()
  • second Component의 ngOnInit()에 있는 데이터(_first ComponentService.retrieveData())를 가져옵니다.

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

일반적으로 컴포넌트 간에 데이터를 전달할 수 있는 다른 잠재적인 접근법이 없는지, 특히 코드 수가 적은지 알고 싶습니다.

업데이트 4.0.0

자세한 내용은 탐색하기 전에 각도 라우터 - 데이터 가져오기를 참조하십시오.

원래의

서비스를 이용하는 것이 좋은 방법입니다.루트 파라미터에서는 브라우저 URL 바에 반영할 데이터만 전달해야 합니다.

Angular Angular Cookbook 구성 요소 통신 - 양방향 서비스를 참조하십시오.

RC에는 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();
  }
}

'플런커'도 참조해 주세요.

angular 1.x처럼 angular 2에는 $rootScope 같은 것이 없기 때문에,ngOnDestroy에서 데이터를 서비스로 전달하고 라우팅 후 ngOnInit 함수로 서비스에서 데이터를 가져올 때 angular 2 공유 서비스/클래스를 사용할 수 있습니다.

여기서는 Data Service를 사용하여 Hero 객체를 공유합니다.

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

첫 페이지 구성 요소에서 개체 전달:

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

두 번째 페이지 구성 요소에서 개체 가져오기:

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

다음은 예를 제시하겠습니다.plunker

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))
  }
}
<div class="button" click="routeWithData()">Pass data and route</div>

angular 6 또는 다른 버전에서 가장 쉬운 방법은 단순히 전달하고 싶은 데이터의 양으로 경로를 정의하는 것입니다.

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

에서 알 수, 는 "My Routes" (루트 정의)를 했습니다./:id라우터 네비게이션을 통해 컴포넌트에 전달하고 싶은 데이터에 대응합니다. 코드 이 '비밀번호'가 '비밀번호'가 .

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

idImport만 .ActivatedRoute

import { ActivatedRoute } from '@angular/router'

및 그 위에ngOnInit입니다.

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

자세한 것은, 이 기사를 참조해 주세요.

이 페이지에서 모든 솔루션을 살펴보았지만(몇 가지 시도도 했습니다), 경로 간에 데이터를 전송하기 위해 해킹과 같은 방법을 구현해야 한다는 확신이 들지 않았습니다.

history.state 입니다.state.script, scriptscript 、 JavaScript 、 됩니다다다됩됩 。

그래서 Angular v10(Ionic v5) 어플리케이션에서는 이렇게 했습니다.

this.router.navigateByUrl('/authenticate/username', {
    state: {user: new User(), foo: 'bar'}
});

여기에 이미지 설명 입력

그리고 네비게이션 컴포넌트('/authenticate/username' »ngOnInit(), 법, the, 이, 데, 했, 했, 했, 했, 했, method, method, method, method, method.this.router.getCurrentNavigation().extras.state-

ngOnInit() {
    console.log('>>authenticate-username:41:',
        this.router.getCurrentNavigation().extras.state);
}

여기에 이미지 설명 입력

그리고 나는 통과된 원하는 데이터를 얻었다.

여기에 이미지 설명 입력

지금은 2019년이고, 여러분이 무엇을 하고 싶은지에 따라 여기 있는 많은 대답들이 효과가 있을 것입니다.되지 않는 는, URL 를 사용할 수 .state(오늘 배운 바와 같이) 7.2 이후입니다.

블로그(Credits Tomasz Kula)에서 경로로 이동합니다.

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

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

대상 컴포넌트에서 픽업하려면:

constructor(public activatedRoute: ActivatedRoute) {}

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

늦었지만, 이게 최근 앵귤러 환자한테 도움이 됐으면 좋겠네요

내가 아닌 매우 똑똑한 사람(tmburnell)이 경로 데이터를 다시 쓰라고 제안합니다.

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

여기 댓글에서 보듯이.

누군가 이것을 유용하게 여겨주길 바란다.

다른 접근법은 이 문제에 좋지 않습니다.가장 좋은 접근법은 Query-Parameter by 입니다.Router: 2방향의 각도:

쿼리 매개 변수 직접 전달

하면, 「 」에 할 수 있습니다.url타타에 params코드 내: html 코드 내:

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

ActiveRoute를 사용한 솔루션(루트별로 객체를 전달하려면 JSON.stringfy/J 사용)SON.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"]);
      });
  }

}

루트:

{ path: 'foo-route', component: FooComponent, data: { myData: false } },

구성 요소에서 데이터 개체에 한 번 액세스합니다.

pipe(take(1)) 실행되므로 하지 않으며 해제할 .

constructor(private activatedRoute: ActivatedRoute) { ... }

ngOnInit(): void {
  this.activatedRoute.data.pipe(take(1)).subscribe((data) => {
    console.log(data); // do something with the data
  });
}
  • 필요한 물건을 수입하는 것을 잊지 않다

: ★★★★★★★firstValueFrom() 좋을 수도 요.

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

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
}

JSON을 사용한 패스

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

공유 서비스를 사용하여 사용자 지정 인덱스로 데이터를 저장한 다음 해당 사용자 지정 인덱스를 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']];
        }
    );
}

가지고 있다고 하다

  1. 컴포넌트1.ts
  2. 컴포넌트1.1.16

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

라우팅된 컴포넌트 간에 데이터를 공유하기 위해 BehaviorSubject를 사용할 수 있습니다.Behavior Subject에는 1개의 값이 있습니다.서브스크라이브되면 즉시 값이 방출됩니다.제목에 값이 없습니다.

복무 중.

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

참고: 여기서는 제목이 작동하지 않습니다. 동작 제목만 사용해야 합니다.

기본적으로는 이 루트에 대한 가드는 사용하지 않습니다.경로에 들어갈 수 있는지 나갈 수 있는지 여부가 더 중요합니다.그것은 그들 사이에 데이터를 공유하는 것이 아니다.

루트에 들어가기 전에 데이터를 로드하려면 이 루트에 리졸버를 추가하면 됩니다.이것도 라우터의 일부입니다.

매우 기본적인 예로서 다음과 같습니다.

리졸바

import { Resolve, ActivatedRoute } from "@angular/router";
import { Observable } from "rxjs";
import { Injectable } from "@angular/core";
import { take } from "rxjs/operators";

@Injectable()
export class UserResolver implements Resolve<User> {

    constructor(
        private userService: UserService,
        private route: ActivatedRoute
    ) {}

    resolve(): Observable<firebase.User> {
        return this.route.params.pipe(
            switchMap((params) => this.userService.fetchUser(params.user_id)),
            take(1)
        );
    }
}

라우터에 넣습니다.

RouterModule.forChild([
{
    path: "user/:user_id",
    component: MyUserDetailPage,
    resolve: {
        user: UserResolver
    }
  }
}]

컴포넌트에 데이터를 입력하다

ngOnInit() {
    const user: firebase.User = this.activatedRoute.snapshot.data.user;
}

이 접근법의 단점은 사용자 데이터를 취득하지 않은 경우 먼저 경로를 입력한다는 것입니다.이것에 의해, 유저의 데이터가 로드되어 컴포넌트의 기동시에 준비가 끝난 상태로 되어 있습니다만, 데이터가 로드되고 있는 동안은 낡은 페이지를 계속 유지할 수 있습니다(애니메이션 로드).

하나의 훌륭한 솔루션은 canActivate 메서드를 사용하여 가드를 구현하는 것입니다.이 시나리오에서는 지정된 api에서 데이터를 가져와 사용자가 라우팅 파일에 설명된 구성 요소에 액세스할 수 있도록 할 수 있습니다.그 사이에 루트 오브젝트의 데이터 속성을 설정하고 컴포넌트 내에서 취득할 수 있다.

예를 들어 다음과 같은 라우팅 컨피규레이션이 있다고 합니다.

const routes: Routes = [
    { path: "/:projectName", component: ProjectComponent, canActivate: [ProjectGuard] }
]`

가드 파일에는 다음과 같은 것이 있습니다.

canActivate(next: ActivatedRouteSnapshot,state: RouterStateSnapshot)
: Observable<boolean> | Promise<boolean> | boolean {
return this.myProjectService.getProject(projectNameFoundElsewhere).pipe(
  map((project) => {
    if (project) {
      next.data = project;
    }
    return !!project;
  }),
);

}`

다음으로 컴포넌트에

constructor(private route: ActivatedRoute) {
    this.route.data.subscribe((value) => (this.project = value));
}

이 방법은 서비스가 설정 해제되지 않은 한 behaviorSubject에 값을 유지하므로 서비스를 경유하는 것과는 조금 다릅니다.가드를 통과하면 현재 경로에 대한 데이터를 사용할 수 있습니다.어린이 루트가 데이터를 보관하고 있는지 확인할 수 없습니다.

데이터를 다른 경로로 전달해야 하는 시나리오에서는 { window.localStorage}를 사용하는 것이 가장 간단한 솔루션입니다.또한 사용이 종료된 후에는 로컬 스토리지에서 데이터를 삭제해야 합니다.이 데이터를 정리하기 위해 ngOnDestroy의 destroy() 메서드를 사용했습니다.또한 페이지 새로 고침을 통해 데이터가 손실되는 문제도 해결됩니다.

클래스 오브젝트의 컬렉션/어레이를 기반으로 작성된 몇 개의 ng 컴포넌트를 처리하는 수식 컬렉션이 있는 경우, 예를 들어 입력값, 공칭값, 최소 단위 및 부언 등 약 10개의 소품을 보유하여 페이지 상태(입력+결과)가 중복되는 많은 것으로 끝납니다.

따라서 *ngif를 사용하여 단일 페이지의 관련 부품(컴포넌트)을 표시하지만 URL은 변경하지 않고 라우팅을 시뮬레이트합니다.

<div *ngIf="visibleComponentA>
... All part of ComponetA 
  ></div>

CpmponetA.html

<div *ngIf="visibleComponentB>
... All part of ComponetB 
  ></div>

CpmponetB.html

이 부울은 컴포넌트의 관련 코드 내에서 설정됩니다.

@Input()visibleComponentA: boolean = true; 

컴포넌트 A.ts

이제 맨 위 페이지로 이동

<div (click)="OnClickNav(visibleComponentA)" >ComponentA</div>
<div (click)="OnClickNav(visibleComponentB)" >ComponentB</div> 

app.component.module

OnClickNav 메서드(선택:NavFlags)를 사용하여 컴포넌트의 올바른 표시 상태를 전환합니다.

OnClickNav(Selected:NavFlags){

    Selected.NavStatus=!Selected.NavStatus

    Selected.NavItem=='visibleComponetA'? this.visibleComponetA.NavStatus=Selected.NavStatus: this.visibleComponetA.NavStatus= false;
    Selected.NavItem=='visibleComponetB'? this.visibleComponetB.NavStatus=Selected.NavStatus: this.visibleComponetB.NavStatus= false;

app.commonet.ts

NavFlags 클래스는 단순합니다.

export class NavFlags {
  NavItem: string = '';
  NavStatus: boolean = false;

  constructor(NavItem: string, NavStatus: boolean) {
    this.NavItem = NavItem;
    this.NavStatus = NavStatus;
  }
}

nav-param.ts

이것에 의해, 「개별」페이지에 데이터가 없어지는 일은 없습니다.중복 스토어는 없습니다.완전한 예는 https://angulartool.de에서 확인할 수 있습니다.버튼을 클릭하면 컴포넌트의 페이지를 데이터 손실 없이 이동할 수 있습니다.

이 해킹은 완벽하지 않으니 이 각진 물질을 해결할 더 좋은 방법이 있을지도 몰라.

언급URL : https://stackoverflow.com/questions/36835123/how-do-i-pass-data-to-angular-routed-components