【问题标题】:Angular / TypeScript, when using multiple components, 1st component affect 2nd componentAngular / TypeScript,当使用多个组件时,第一个组件影响第二个组件
【发布时间】:2018-05-18 23:24:12
【问题描述】:

我创建了一个库 Angular-Slickgrid,它是 jQuery 数据网格库的包装器,并且是开源的。当页面上只有 1 个网格(组件)时,这一切都很好,但是当我想在同一页面上创建 2 个这些组件(相同的选择器)时,我开始得到很多奇怪的行为。我可以看到的行为是一些第一个功能会影响第二个网格。我可以处理服务单例,但在我的情况下,实际上是组件的属性被最后创建的组件覆盖,这是为什么呢?我认为每个 Angular 组件都是完全独立的(除了服务),那么我做错了什么?

我使用ng-packagr 创建我的库,组件的ngModule 如下

@NgModule({
  imports: [
    CommonModule,
    TranslateModule
  ],
  declarations: [
    AngularSlickgridComponent,
    SlickPaginationComponent
  ],
  exports: [
    AngularSlickgridComponent,
    SlickPaginationComponent
  ],
  entryComponents: [AngularSlickgridComponent]
})
export class AngularSlickgridModule {
  static forRoot(config: GridOption = {}) {
    return {
      ngModule: AngularSlickgridModule,
      providers: [
        {provide: 'config', useValue: config},
        CollectionService,
        ControlAndPluginService,
        ExportService,
        FilterService,
        GraphqlService,
        GridEventService,
        GridExtraService,
        GridOdataService,
        GridStateService,
        GroupingAndColspanService,
        OdataService,
        ResizerService,
        SharedService,
        SortService
      ]
    };
  }
}

组件类以

开头
@Injectable()
@Component({
  selector: 'angular-slickgrid',
  templateUrl: './angular-slickgrid.component.html',
  providers: [ResizerService]
})
export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnInit {

然后在我的应用程序中,我像这样调用外部网格模块

imports: [
  AppRoutingRoutingModule,
  BrowserModule,
  HttpClientModule,
  TranslateModule.forRoot({
    loader: {
      provide: TranslateLoader,
      useFactory: (createTranslateLoader),
      deps: [HttpClient]
    }
  }),
  AngularSlickgridModule.forRoot({
    // add any Global Grid Options/Config you might wantApp
    enableAutoResize: true
  })
],

然后我可以像这样在我的视图中创建 2 个网格

    <angular-slickgrid gridId="grid1"
          [columnDefinitions]="columnDefinitions"
          [gridOptions]="gridOptions"
          gridHeight="200"
        gridWidth="800"
          [dataset]="dataset">
</angular-slickgrid>

<hr>

<angular-slickgrid gridId="grid2"
          [columnDefinitions]="columnDefinitions2"
          [gridOptions]="gridOptions2"
          gridHeight="200"
        gridWidth="800"
          [dataset]="dataset2">
</angular-slickgrid>

花了很多时间调试后,我确实发现第一个组件完全覆盖了第二个组件的属性。如果我销毁第二个组件,它不会解决问题。例如,我单击一个列在两个网格上对其进行排序,当我从第一个网格单击“clearSort()”时,它实际上清除了第二个网格的排序!?我还发现只有最后创建的网格的属性仍然存在,如果我从第一个或第二个网格单击“clearSort()”,它将始终在第二个网格中清除它。

我知道如何处理服务单例,但我的问题实际上是两个组件以某种方式共享的类的属性......或者从另一个角度来看,第一个组件类属性被第二个组件覆盖属性

我是否缺少使这两个组件完全独立的东西?我已经搜索和尝试了几个小时,这是可能的还是正常的行为?

编辑

如果你想看所有代码,一切都可以从 GitHub 获得,你可以看 2 个网格代码(目前在一个单独的分支上):

编辑 2 经过这么多小时后,我发现它与 Services Singleton 有关。在下面回答了我自己的问题。希望这会帮助其他面临类似问题的人。

查看下面的行为,查看数据以及蓝色排序图标,这一切都发生在第二个网格上,而我在第一个网格上执行操作

【问题讨论】:

    标签: javascript angular typescript


    【解决方案1】:

    两个组件实例,即使是同一个组件类,也应该有自己的范围。如果它们未声明为静态变量,则它们的变量是封装的并且是唯一的。

    您确定 dataset 和 dataset2 不共享相同的引用吗?避免跟随,即使是测试:

    private dataset = [data1, data2];
    private dataset2 = dataset;
    

    如果您将 dataset 和 dataset2 输入到两个不同的组件,这将强制执行所描述的怪异行为。

    您正在包装一个 jquery 插件,它本身就是纯 javascript。也许包装好的 javascript 正在撤销 angulars 组件范围?

    您确定组件实例不会错误地被服务共享数据吗?

    【讨论】:

    • 我更新了我的问题以提供所有必要代码的链接。问题不在于数据集,而是gridgridOptionsdataView 对象似乎都是共享的(覆盖),我不明白为什么。应用程序似乎没有与 2 个网格共享任何内容。从第一个网格发生在第二个网格上的清晰排序,不仅是数据集大小,而且还对在第二个网格而不是第一个网格中消失的图标和数据进行排序
    【解决方案2】:

    哇,我发现了问题,没想到我发现的问题是……我的库中没有providers,因此所有服务都充当单例。因此,任何服务函数调用都使用最后创建的网格的内部变量(gridgridOptionsdataView)。因此,为了解决这个问题,我唯一要做的就是将所有服务提供到 providers 数组中。

    之前

    @Injectable()
    @Component({
      selector: 'angular-slickgrid',
      templateUrl: './angular-slickgrid.component.html',
      providers: [ResizerService]
    })
    

    导出类 AngularSlickgridComponent 实现 AfterViewInit、OnDestroy、OnInit {

    之后

    @Injectable()
    @Component({
      selector: 'angular-slickgrid',
      templateUrl: './angular-slickgrid.component.html',
      providers: [
        ControlAndPluginService,
        ExportService,
        FilterService,
        GraphqlService,
        GridEventService,
        GridExtraService,
        GridStateService,
        GroupingAndColspanService,
        ResizerService,
        SortService
      ]
    })
    export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnInit {
    

    哦,天哪……为了这么简单的事情浪费了这么多时间

    【讨论】:

      猜你喜欢
      • 2016-08-21
      • 1970-01-01
      • 1970-01-01
      • 2017-09-06
      • 2018-09-16
      • 2018-09-14
      • 2018-10-17
      • 1970-01-01
      • 2011-05-16
      相关资源
      最近更新 更多