【问题标题】:Angular 2 how to pass variable from parent component to router outletAngular 2如何将变量从父组件传递到路由器出口
【发布时间】:2016-06-05 07:36:02
【问题描述】:

我发现的所有教程和答案仅显示了如何使用输入将变量从父组件传递到子组件,但是这个子组件是包含在路由器插座中而不是直接在父模板中??

例如:

主要组件

@Component({
  selector: 'my-app',
  template: `
          Main page
          <router-outlet></router-outlet>
              `,
  directives: [ROUTER_DIRECTIVES]
})

@RouteConfig([
    { path: '/contact', name: 'Contact', component: ContactComponent},
 ])

export class AppComponent{
  public num:Number = 123;
}





@Component({
   selector: 'contact-page',
   template: 'contact page'
})
export class ContactComponent{
   public num:Number;
}

所以在这个例子中,主组件模板包含一个路由器出口,子联系人组件将在其中呈现,但是我如何从父应用程序组件的路由器出口内评估子组件中的变量“num”值??

【问题讨论】:

标签: components angular router


【解决方案1】:

我只是偶然发现了这个问题,这是我解决类似问题的方法。

我会使用服务来解决这个问题。然后,所有子级和父级都可以设置该属性,并将更改传播给所有订阅者。首先,我将创建一个具有私有 BehaviorSubject 的服务,该服务具有公共 getter 和 setter,以封装 ReplaySubject 并仅返回 Observable:

private _property$: BehaviorSubject<number> = new BehaviorSubject(1);

set property(value: number) {
    this._property$.next(value);
}

get property$(): Observable<number> {
    return this._property$.asObservable();
}

之所以使用new BehaviorSubject(1),是为了将初始值设置为1,这样就可以订阅了。

在父母 onInit 中,我会设置属性 (num) 的默认值:

private _propertySubscribtion: Subscription

ngOnInit() {
    // set default value to 5
    this._componentService.property = 5;

    // If property is updated outside parent
    this._componentService.property$.subscribe(p => {
        this.property = p;
    });
}

ngOnDestroy() {
    this._propertySubscribtion.unsubscribe();
}

在一个或多个子组件中,可以订阅更改:

private _propertySubscribtion: Subscription

ngOnInit() {
    this._propertySubscribtion = this._componentService.property$.subscribe(p => {
        this.property = p;
    });
}

ngOnDestroy() {
    this._propertySubscribtion.unsubscribe();
}

如果某些孩子或父母更新了属性:

updateProperty() {
    // update property
    this._componentService.property = 8;
}

所有订阅者都会知道。

【讨论】:

  • 有没有什么方法可以在第一次发射后删除属性值而不更新属性?
  • 将值设置为 null 是否足够。我有时会在 http 请求完成之前使用 null 值作为初始值。
  • 是的。我最初也将其设置为 null,然后在操作后再次将值设置为 null。谢谢你...
  • 记得退订,我不知道你的设置,但要确保你的组件在不需要时不会被调用:)
  • 您的解决方案帮助很大。除了这个还有其他方法可以传递值吗???
【解决方案2】:

目前您无法绑定到路由器添加的组件。改用共享服务(这里已经有大量关于 SO 的示例)从添加的组件传递数据或向其传递数据或订阅事件。

另请参阅此问题https://github.com/angular/angular/issues/4452 尤其是此评论https://github.com/angular/angular/issues/4452#issuecomment-153889558

【讨论】:

  • 如果您认为共享服务并不理想,例如,您有一项服务可以从数据库中获取所有应用程序设置,并且您需要在主要组件上显示其中一些设置,例如在页面顶部或电话号码,然后您需要通过路由器插座在联系人页面上显示相同的内容,如果您使用服务,您将在同一页面上进行两次 ajax 调用以获得相同的详细信息。希望你明白我的意思。
  • 实际上我看不出使用服务和“两次执行 ajax 调用”有什么关系。您可以使用服务来传递来自ParentComponent 的数据(包含&lt;router-outlet&gt; 和添加到&lt;router-outlet&gt; 的组件,方法是将其添加到ParentComponent 的提供者列表中。这样服务仅在@ 之间共享987654327@ 及其后代。共享服务本身可以依赖于执行 ajax 调用的全局服务,例如,如果之前已获取数据,则返回缓存结果。
  • 我理解你的意思,但我正在寻找的想法是不必从父母那里两次获取结果,一次从孩子那里获取相同的信息。当然,缓存结果的想法可以防止这种双重获取,但是如果你在父组件中获取结果并且你可以将它传递给它的孩子,我无法绕开我的头,你可以将它传递给它的孩子为什么我不能这样做如果这种情况下的孩子包含在路由器插座内?必须有一个更简单的逻辑来解决这个问题。
  • 我猜你只是想多了。目前绑定不适用于动态添加的组件(通过路由器或 DynamicComponentLoader)。您使用服务而不是绑定。除了更多样板(创建服务类、添加字段和事件发射器或主题、将服务添加到提供程序、读取、写入、订阅父子节点的输入/输出)之外,这并没有太大的区别。但除此之外,唯一的区别是孙子也可以访问该服务,而 Binding 仅适用于直系子孙。
  • 我同意这适用于本示例,但假设您想通过路由组件中的元标题变量更改父组件中包含的页面元标题,或者您在父组件中有一个顶部购物车组件,您需要使用来自购物车页面的新数量和价格更新它,其中购物车包含在路由器插座甚至面包屑......等中。许多示例表明,您需要在路由组件与其父组件之间进行某种交互,您不能在每种情况下都将它们隔离并使用共享服务。希望你能看到这里的大问题。
【解决方案3】:

如果你的数据是不可变的,你可以使用RouteData

@Component({...})
@RouteConfig([
    { path: '/contact', name: 'Contact', component: ContactComponent, data: {num: 123}},
 ])
export class AppComponent {
}

@Component({...})
export class ContactComponent {
   public num:Number;
   constructor(data: RouteData) {
     this.num = data.get('num');
   }
}

传递一些您不想在子路由中硬编码的配置选项可能很有用。但如果您希望数据发生变化,则需要其他方法。

【讨论】:

  • 这在 Angular 2 路由器的最新版本中已被弃用。
猜你喜欢
  • 2020-03-01
  • 2017-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-08
  • 2016-07-06
相关资源
最近更新 更多