在我的Angular 2路由模板之一(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
    }
}

通常我会通过

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

最终传递数据

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

而带有参数的链接的定义将是

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

这种方法的问题是,我猜我不能在url中传递复杂的数据(例如property3这样的对象);

2方法

另一种方法是在FirstComponent中包含SecondComponent作为指令。

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

然而,我想路由到该组件,不包括它!

第三个方法

我在这里看到的最可行的解决方案是使用一个服务(例如FirstComponentService)来

将数据(_firstComponentService.storeData())存储在FirstComponent的routeWithData()上 在SecondComponent的ngOnInit()中检索数据(_firstComponentService.retrieveData())

虽然这种方法似乎完全可行,但我想知道这是否是实现目标的最简单/最优雅的方法。

一般来说,我想知道我是否错过了在组件之间传递数据的其他潜在方法,特别是在代码量可能较少的情况下


当前回答

如果你有一个公式集合,它处理了几个ng组件,这些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; 

ComponetA.ts

现在在第一页

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

app.component.html

和方法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-flags.ts

这样,“个人”页面就不会留下任何数据丢失。我没有复制商店。 完整的示例可以访问https://angulartool.de。 通过单击该按钮,可以在组件中导航页面,而不会丢失数据。

这个hack不是完美的,所以也许会有更好的方法来解决这个角度问题。

其他回答

我认为另一种方法对这个问题不好。 我认为最好的方法是路由器角度的查询参数,有两种方式:

直接传递查询参数

有了这段代码,你可以在html代码中通过参数导航到url:

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

通过路由器传递查询参数

你必须像这样在构造函数中注入路由器:

constructor(private router:Router){

}

现在用这个短语:

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

现在,如果你想从另一个组件的路由器读取,你必须使用ActivatedRoute:

constructor(private activateRouter:ActivatedRouter){

}

并订阅:

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

默认情况下,我不会使用一个守卫这一个对我来说,这是更多的我可以进入路线或我可以离开它。这不是为了在它们之间共享数据。

如果你想在我们进入路由之前加载数据,只需添加一个解析器,这也是路由器的一部分。

举个非常基本的例子:

解析器

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

这种方法的缺点是,如果他之前没有得到用户数据,他将首先进入路由,这确保用户的数据已经加载并在组件开始时准备好了,但只要数据已经加载,你就会停留在旧页面上(加载动画)

使用JSON传递

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

在需要将数据传递到另一个Route的场景中,最好和最简单的解决方案是使用{window。localStorage}。此外,不要记得在数据使用结束后从本地存储中删除数据。 我使用ngOnDestroy的destroy()方法来清理这些数据。 这也解决了页面刷新丢失数据的问题。

说你有

component1.ts component1.html

您希望将数据传递给component2.ts。

in component1.ts is a variable with 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"} }); }