在我的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())

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

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


当前回答

更新4.0.0

更多细节请参见Angular Angular Router -在导航前获取数据。

原始

使用服务是正确的选择。在路由参数中,您应该只传递希望在浏览器URL栏中反映的数据。

参见Angular Cookbook组件通信-双向服务。

RC.4附带的路由器重新引入了数据

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。

其他回答

一些超级聪明的人(tmburnell)(不是我)建议重写路由数据:

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

正如你在评论中看到的。

我希望有人会觉得这有用

如果你有一个公式集合,它处理了几个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不是完美的,所以也许会有更好的方法来解决这个角度问题。

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

Or:

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

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

直接传递查询参数

有了这段代码,你可以在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;
      });
  }

现在是2019年,这里的许多答案都有用,这取决于你想做什么。如果你想传递一些URL中不可见的内部状态(params, query),你可以从7.2开始使用state(正如我今天刚刚学到的:))。

从博客(Tomasz Kula) -您导航到....路线

…来自ts: this.router。navigateByUrl('/details', {state: {hello: 'world'}});

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

并在目标组件中拾取它:

constructor(public activatedRoute: ActivatedRoute) {}

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

有点晚了,但希望这能帮助到刚接触Angular的人。