每个(一组)组件的 angular 服务的单独实例

Seperate instances of an angular service per (set of) component(s)

TLDR:

如何将 Angular (6) 服务的一个实例用于一组(的实例)组件(和指令),并将另一个实例用于另一组相同的组件。

或提供更多信息:

我目前正致力于在基于 Angular 6 的应用程序中向 tables 添加排序功能。因为我使用的是自定义样式(基于具体化),所以大多数库都不适合我。我发现 this 很好的例子,尽管它完全独立于所使用的样式。

它创建一个 SortableColumnComponent 添加到每个 <th> header 和一个 SortableTableDirective 添加到 <table> 元素。他们通过 SortService 进行通信,该 SortService 基本上只提供一个 RxJS 主题,以便在排序 direction/attribute 更改时通知其他列。

这里的问题是,只要一次只显示一个 sortable table,这个方法就很好用。但是,一旦添加更多,排序一次只能应用于一个(因为它们都共享相同的服务)。

根据 angular docs ,当您仅将服务注入应用程序根目录时(我这样做了),服务会自动变成单例。所以我试着只将它注入 sortableColumn:

@Component ({
    selector: '[sortable-column]',
    templateUrl: './sortable-column.component.html'
    providers: [SortService]
})

但是每一列似乎都有自己的服务版本并且可以同时排序(这显然不能按预期工作)。

所以总的问题是:如何将 angular 服务的一个实例分配给一个(一个)组件(SortableTableDirective)和匹配的 SortableColumnComponent 组件和其他 tables.

的同一服务的另一个实例

为了让这个更清楚,这就是我想要实现的目标:

-------------------------------------------------------------------------
| page                                                                  |
|                                                                       |
| table 1 - SortableTableDirective - using instance 1 of sortingservice |
|   th 1 - sortablecolumncomponent - using instance 1 of sortingservice |
|   th 2 - sortablecolumncomponent - using instance 1 of sortingservice |
| ....                                                                  |
| table 2 - SortableTableDirective - using instance 2 of sortingservice |
|   th 1 - sortablecolumncomponent - using instance 2 of sortingservice |
|   th 2 - sortablecolumncomponent - using instance 2 of sortingservice |
-------------------------------------------------------------------------

或者有没有办法直接将某些列组件绑定到 table 指令并删除该服务?我在这里似乎缺少 "linking" 这个概念。

您不应在组件中提供服务,而应在 AppModule 中提供服务,并且 'inject' 通过在构造函数中创建属性来提供您的服务。

service.ts

@Injectable({
  providedIn: 'root'
})

export  class MyService {
}

编辑:

component.ts

@Component ({
    selector: '[sortable-column]',
    templateUrl: './sortable-column.component.html'
})

constructor(private myService: MyService) {}

appModule.ts

@NgModule({
declarations:[component], 
imports: [YourModules], 
providers: [MyService],
bootstrap: [component]
})
export class AppModule {}

阅读更多内容后,我发现另一个 part of the angular docs(最后一段)终于让我走上了正确的轨道:您可以通过将提供程序加载到组件中来限制它的范围。然后它仅对组件及其子组件可用(!)。在这种情况下正是我需要的。

当我第一次尝试时,我犯了一个错误,即在列中加载服务,从而为每个服务提供不同的实例。在 table 指令中加载它效果很好,因为这为 table 和所有子元素(例如列)提供了一个实例。 table 指令的另一个实例然后加载该服务的另一个实例,它允许我对所有 table 进行独立排序。

代码:

@Directive({
  selector: '[sortable-table]',
  providers: [SortService]
})

为了将来救人,现在我们可以使用Hierarchical Dependency Injection

在 Table 组件中,将您的服务放在 [providers] 中,并使用 @Host 装饰器标记依赖注入。在children中,标记为@SkipSelf.

现在,children 将忽略它们的“自身”实例并开始在标有@Host 的parent 中搜索服务。

查看示例:

Parent

@Component({
    selector: 'table-component',
    providers: [TableService],
    templateUrl: './table.component.html',
    styleUrls: ['./table.component.scss'],
})
export class TableComponent {
    constructor(@Host() private tableService: TableService)
}

Child

@Component({
    selector: 'child-component',
    templateUrl: './child.component.html',
    styleUrls: ['./child.component.scss'],
})
export class ChildComponent{
    constructor(@SkipSelf() private tableService: TableService)
}