【问题标题】:How to initialize Providers passing component attributes as parameter in angular 2如何在角度2中初始化将组件属性作为参数传递的提供者
【发布时间】:2017-03-09 10:06:09
【问题描述】:

我有一个名为workspace 的组件,它应该提供一个名为DbService 的服务。 此服务旨在供workspace 的子组件使用。 DbService 有一个参数path

我希望能够按如下方式初始化我的组件:

<workspace db="/a/b/c"></workspace>
<workspace db="/d/e/f"></workspace>

并确保在工作区中初始化的每个DbService 提供程序都可以访问其构造函数中的 db 属性值。 dbService 也是异步初始化的。理想情况下,应在 dbService 完全初始化后初始化子组件。

我尝试了很多不同的方法,但到目前为止都没有成功。

使用来自组件属性的参数异步初始化Provider 的推荐方法是什么?

【问题讨论】:

    标签: angular dependency-injection


    【解决方案1】:

    您要做的是将组件更改检测策略设置为 OnPush。基本上所做的是,变化检测只会在输入变化时运行。下一部分是将要在组件中运行的任何逻辑挂钩到 ngOnChanges() 方法中,该方法将在每次通过您控制的输入为组件补充水分时触发,因此您的数据库服务将始终使用正确的路径进行初始化:

    import {Component, ChangeDetectionStrategy} from "@angular/core";
    
    @Component({
        changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class WorkspaceComponet
    {
        @Input() db;
    
        constructor(private dbService: DbService)
        {
        }
    
        ngOnChanges()
        {
            this.dbService.init(this.db)
        }
    
    }
    

    【讨论】:

    • 如何通知子组件有关 this.dbService.init(this.db) 触发的异步初始化?
    【解决方案2】:

    在您的 DbService 上有一个显式的 init 方法,然后执行以下操作:

    <workspace [db]="a/b/c"></workspace>
    
    export class WorkspaceComponent{
      @Input() db;
    
      constructor(private dbService: DbService){
        dbService.init(db)
      }
    }
    

    【讨论】:

    • 这并不能保证 dbService 可供子组件使用。基本上子组件需要完全初始化 dbService。
    【解决方案3】:

    在工作区组件中使用@input db:string 变量并在您使用工作区组件的位置设置 db 变量。

    例如:

    <workspace [db]="/a/b/c"></workspace>
    
    
    @Component({
      selector: 'workspace',
      template: `
        {{db}}
      `
    })
    export class HeroChildComponent {
      @Input() db: string;
    }
    

    【讨论】:

      【解决方案4】:

      这不是 DI 可以单独处理的事情,因为在实例化服务时属性不可用。

      解决方法是

      class DbServiceContainer {
        instance: DbService;
      }
      
      @Component({
        ...
        providers: [DbServiceContainer]
      })
      class WorkspaceComponent {
        constructor(@Attribute('db') db, dbServiceContainer: DbServiceContainer) {
          dbServiceContainer.instance = new DbService(db);
        }
      }
      
      @Component({ ... })
      class WorkspaceChildComponent {
        dbService: DbService;
      
        constructor(dbServiceContainer: DbServiceContainer) {
          this.dbService = dbServiceContainer.instance;
        }
      }
      

      【讨论】:

      • 新的 DbService(db);不保证立即可用,因此子组件无法在所需时间使用。
      • 什么是“所需时间”?如示例所示,它可以在子组件构造函数中使用。这个问题没有解释为什么这种方法会出现问题。如果 dbService 是异步初始化的,那么它应该返回一个 promise 或 observable。
      • 'desired time' 我的意思是孩子们可以参考它,但如果他们现在可以开始使用它,他们仍然应该现在或现在。如果 dbService 提供了一个 observable,我如何保证它只会在所有子组件初始化后才通知?
      • 一个 promise/observable 解决了这个问题,我认为它没有任何问题。子项的初始化不能“延迟”。通常路由解析器用于获取组件中的异步依赖项,但为了方便起见,它们通常也包含可观察对象,我认为这种方法不能很好地与您尝试使用 db 属性做的事情。
      • 感谢您迄今为止的帮助。有了承诺,担心的是我不想向每个调用者返回承诺。我想检查是否有一种方法可以使用组件本身提供的参数来初始化组件内的服务。显然,没有 promises 和/或 observables 是不可能的......
      猜你喜欢
      • 1970-01-01
      • 2021-11-06
      • 1970-01-01
      • 2014-05-24
      • 1970-01-01
      • 2017-12-31
      • 2014-02-26
      • 2019-06-08
      相关资源
      最近更新 更多