私のAngular 2つのルートのテンプレートのうちの1つに( FirstComponent )ボタンがあります。
first.component.html
<div class="button" click="routeWithData()">Pass data and route</div>
私の 目標 を達成することです:
データを保存しながらディレクティブとして他のコンポーネントを使用せずに、ボタンクリック - >他のコンポーネントへのルーティング。
これは私が試したものです...
1回目のアプローチ
同じ見方で、私はユーザーの対話に基づいて同じデータを集めることを格納しています。
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
}
}
通常私は SecondComponent にルーティングします
this._router.navigate(['SecondComponent']);
最終的にデータを渡す
this._router.navigate(['SecondComponent', {p1: this.property1, p2: property2 }]);
パラメータとのリンクの定義は
@RouteConfig([
// ...
{ path: '/SecondComponent/:p1:p2', name: 'SecondComponent', component: SecondComponent}
)]
このアプローチの問題点は、 複雑なデータを渡すことができないことです (例: object like property3);
第2アプローチ
別の方法としては、FirstComponentに directive としてSecondComponentを含めることができます。
<SecondComponent [p3]="property3"></SecondComponent>
ただし、そのコンポーネントに route を付けたいのですが、含めないでください。
3次アプローチ
私がここで見る最も実行可能な解決策は Service (例えばFirstComponentService)を使うことでしょう。
このアプローチは完全に実行可能に思えますが、これが目標を達成するための最も簡単でエレガントな方法であるかどうか私は疑問に思います。
一般的に、コンポーネント間でデータをやり取りするための他の 潜在的なアプローチ がないかどうかを知りたいのですが、特に 可能な限り少ないコードで
4.0.0を更新
詳細についてはAngular docsを参照してください https://angular.io/guide/router#fetch-data-before-navigating
オリジナル
サービスを利用するのがよい方法です。 route paramsでは、ブラウザの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();
}
}
にあるPlunkerも参照してください。https://github.com/angular/angular/issues/9757#issuecomment-229847781
Angular 1.xのようにAngular 2に $ rootScope のようなものはないので、私は思います。 ngOnDestroy の中で角度2共有サービス/クラスを使用することができ、データをサービスに渡し、ルーティング後に ngOnInit 関数でサービスからデータを取得します。
ここでは、ヒーローオブジェクトを共有するためにDataServiceを使用しています。
import { Hero } from './hero';
export class DataService {
public hero: Hero;
}
最初のページコンポーネントからオブジェクトを渡します。
ngOnDestroy() {
this.dataService.hero = this.hero;
}
2番目のページコンポーネントからオブジェクトを取得します。
ngOnInit() {
this.hero = this.dataService.hero;
}
例を示します。 plunker
<div class="button" click="routeWithData()">Pass data and route</div>
angular 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/
3つ目の方法は、コンポーネント間でデータを共有するための最も一般的な方法です。関連コンポーネントに使用したいアイテムサービスを注入することができます。
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
}
私ではないある賢い人(tmburnell)は、経路データを書き直すことを提案します。
let route = this.router.config.find(r => r.path === '/path');
route.data = { entity: 'entity' };
this.router.navigateByUrl('/path');
見たとおり ここ コメント中。
誰かがこれが役に立つことを願っています
JSONを使って渡す
<a routerLink = "/link"
[queryParams] = "{parameterName: objectToPass| json }">
sample Link
</a>
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"]);
});
}
}
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))
}
}
私はこれがこの問題には良くないもう一つのアプローチです。私は最善のアプローチは Query-Parameter 2つの方法があるRouter
angleによるものです:
クエリパラメータを直接渡す
このコードを使用すると、htmlコードでurl
によってparams
に移動できます。
<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;
});
}
共有サービスを使用してカスタムインデックス付きのデータを保存します。それから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']];
}
);
}
ナビゲーションURLのクエリ文字列内でユーザーにデータを公開したくない場合は、localStorageを使用して2つの異なるコンポーネントルート間で要求されたデータを渡すことができます。
プログラム的に移動する前に
localStorage.setItem("myHiddenData", JSON.stringify(routeData));
this.router.navigate(["route"]);
2番目のコンポーネントの内部ngOnInit
ngOnInit(): void {
this.dataFromRoute = localStorage.getItem("myHiddenData");
}
(オプション)ルータガード
ユーザーがルートデータなしでこのページにアクセスしたくない場合は、この特定のコンポーネントに関連付けられたcanActivateルートガードを作成して、データがlocalStorage内で正しく設定されているかどうかを確認します
canActivate(): boolean {
if (localStorage.getItem("myHiddenData")) {
return true;
} else {
// redirect
this.router.navigate("Home");
return false;
}
この回避策は少し冗長ですが、ユーザーが要求されたデータのみを使用してこのページにアクセスし、実際には渡されたデータをユーザーが簡単に変更できないようにする場合に役立ちます。
あなたがいると言う
そして component2.ts にデータを渡したいとします。
component1.tsでは、データを含む変数です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"}
});
}