【问题标题】:How do I share information with child routes in Angular 2?如何在 Angular 2 中与子路由共享信息?
【发布时间】:2016-09-02 22:23:50
【问题描述】:

我有一个应用程序,其路由如下所示:

/:partner/login
/:partner/tools
/:partner/other

目前使用2.0.0-rc.5,我可以非常简单地构建看起来与上面完全相同的路线。但是,这种方法的缺点是每个组件都必须自己提取partner 参数。所以login 路径声明看起来像:

{
    path: ':partner/login',
    component: LoginComponent
}

LoginComponent 看起来像:

export class LoginComponent implements OnInit {
    partner: string;
    constructor(private _route: ActivatedRoute) { }

    ngOnInit() {
        this._route.params.forEach(p => {
            this.partner = p[`partner`];
        });
    }
}

虽然这可以通过 3 条路线进行管理,但从概念上讲,我真正想说的是我有一个 PartnerComponent,它有子路线 login、tools 等。 路由看起来像这样:

{ path: ':partner', component: PartnerComponent
    children: [
        { path: 'login', component: LoginComponent},
        { path: 'tools', component: ToolsComponent}
    ]
 }

并且使用 TypeScript 的继承,我可以为每个子组件创建一个基本组件,例如:

export class BaseComponent implements OnInit {
    partner: string;
    constructor(private _route: ActivatedRoute) { }

    ngOnInit() {
        this._route.parent.params.forEach(p => {
            this.partner = p[`partner`];
        });
    }
}

子组件看起来像:

export class LoginComponent extends BaseComponent {
    constructor(route: ActivatedRoute) {
        super(route);
    }

    ngOnInit() {
        super.ngOnInit();
    }
}

虽然上述方法可行,但查找父路由感觉有点脏。我知道如果我改变层次结构,我只需要在基础中改变它,但仍然

是否有更简洁的方式在父路由组件和其子路由组件之间共享信息。

如果它是更传统的父元素/子元素关系,我们将简单地使用两者之间的数据绑定来传递该信息。

【问题讨论】:

  • 组件数据绑定是不可能的吗?我真的不认为partner 是一个组件,而是作为数据。拥有partner 的组件能否通过数据绑定将其传递给子级(即login、tools、`other)?
  • @KevinLe AFAIK,路由器是解析 URL 和提取参数的支持方式。你是对的,就目前而言,PartnerComponent 除了<router-outlet> 标签之外真的没有太多其他东西。但是,从长远来看,我可以看到这会演变并变得更加复杂。
  • 嗯,仍然不确定您是否需要为 partner 解析 url 本身。我在下面发布了一个答案,看看它是否对你有帮助!不过,您可能已经探索过了。
  • 查看stackoverflow.com/a/39031152/1810391。无需传递父 id,只需在两侧硬编码相同的 shareObj id。您也可以探索方法 2。

标签: angular angular2-routing


【解决方案1】:

您可以做的是为您的父路由使用Resolve 保护,因此将为任何:partner 路由加载数据。

Resolve 看起来像:

import { Injectable }             from '@angular/core';
import { Router, Resolve,
         ActivatedRouteSnapshot } from '@angular/router';

import { Partner } from './partner.model';
import { Api } from './api.service';

@Injectable()
export class PartnerResolve implements Resolve<Partner> {
  constructor(private api: Api,
              private router: Router) {}

  resolve(route: ActivatedRouteSnapshot): Observable<Partner> {
    let id = +route.params['partner'];

    return this.api.getPartner(id);
  }
}

然后,您的路线需要包含PartnerResolve,因此在请求数据并且数据可用之前不会加载:

{
  path: ':partner', component: PartnerComponent,
  resolve: {
    partner: PartnerResolve
  },
  children: [
    { path: 'login', component: LoginComponent},
    { path: 'tools', component: ToolsComponent},
  ]
}

而你的PartnerComponent 会得到它:

ngOnInit() {
  this.route.data.forEach((data: { partner: Partner }) => {
    this.partner = data.partner;
  });
}

您的子组件将使用:

ngOnInit() {
  this.route.parent.data.forEach((data: { partner: Partner }) => {
    this.partner = data.partner;
  });
}

【讨论】:

  • 我正在尝试实现此代码。在这里声明的路线是什么?我发现我需要使用this.route.snapshot.data,但是这个data属性上没有forEach。
  • 没关系。我用这个:this.route.parent.snapshot.data['partner']
【解决方案2】:

将数据从父级传递给子级的另一种方法是使用@Input。

@Component({
   selector: 'partner',
   template: 'partner.html'
   directives: [LoginComponent]
})
export class PartnerComponent {
   partner: string;
}

@Component({
   selector: 'login',
   template: 'login.html'
})
export class LoginComponent {
   @Input() loginPartner: string; //passed in from the parent
}

//partner.html
<div>
   <login [login-partner]='partner'></login>
</div>

参考https://angular.io/docs/ts/latest/cookbook/component-communication.html

【讨论】:

  • 是的,但这假设是静态路由。我描述的路线是动态的,可以是/:partner/login 或/:partner/tools 等。使用您的方法,您必须自己处理子路线。这就是Router 和&lt;router-outlet&gt; 的作用,为您做到这一点。正如您在提供的链接中所说的那样,他们没有提到路由。在路由中,选择器是不必要的,因为组件从不在 HTML 中。看起来他们也推荐服务方法。可能会这样做......
猜你喜欢
  • 2017-10-03
  • 1970-01-01
  • 2018-03-22
  • 1970-01-01
  • 2017-09-18
  • 1970-01-01
  • 2020-01-25
  • 2017-03-28
  • 1970-01-01
相关资源
最近更新 更多