javascript - 订阅派生类上的 Angular2 事件

标签 javascript angular typescript angular2-template angular2-directives

我正在开发一个应用程序,该应用程序在不同页面上使用多个网格。我没有一次又一次地重写 HTML,而是通过以下方式抽象了代码:

table.component.ts

export class TableComponent implements OnInit{
  columns: Column[]= [];
  rows: any[] = [];
  searchText: string;
  routerLinked: string;
  showFilter: boolean;

  constructor(private paginService: PaginationService,
              private tableLoader: GridLoadUtil,
              private progressBarService: ProgressBarService,
              private route: ActivatedRoute,
              private router: Router) {
    this.paginService.itemsToDisplayChange.subscribe((value) => {
      this.rows = value
    });

    this.tableLoader.columnsChange.subscribe((values) => {
      this.columns = values;
    });
  }

  ngOnInit() {
    this.tableLoader.beforeDataLoaded();
    this.progressBarService.startProgress();
    this.routerLinked = this.route.snapshot.url[0].path + '/';
    this.showFilter = true;
  }

  navigateToCreate() {
    this.router.navigate([this.routerLinked]);
  }

  applyFilter() {
    this.paginService.applyFilter(this.searchText);
  }

  clearFilter() {
    this.searchText = '';
    this.paginService.clearFilter();
  }
}

table.component.html

<div class="container container-fluid">
  <div class="row" *ngIf="showFilter === true">
    <div class="form-group">
      <label>Filter </label>
      <input type="text" id="inputName" [(ngModel)]="searchText"/>
      <button type="button" class="btn btn-default btn-sm" (click)="applyFilter()">
        <span class="glyphicon glyphicon-ok"></span>
      </button>
      <button type="button" class="btn btn-default btn-sm" (click)="clearFilter()">
        <span class="glyphicon glyphicon-remove"></span>
      </button>
      <a class="btn btn-default btn-sm pull-right" (click)="navigateToCreate()">
        <span class="glyphicon glyphicon-plus-sign"></span>
      </a>
    </div>
  </div>
  <div class="row">
    <table class="table table-responsive table-hover">
      <thead class="thead-inverse">
      <tr>
        <th *ngFor="let column of columns">{{column.header}}</th>
      </tr>
      </thead>
      <tbody>
      <tr *ngFor="let row of rows;trackBy: trackByID;">
        <td *ngFor="let column of columns">{{row[column.field]}}
        </td>
      </tr>
      </tbody>
    </table>
  </div>
  <xfd-progressbar component></xfd-progressbar>
  <div class="row col-lg-offset-5">
    <ngbd-pagination-basic> component</ngbd-pagination-basic>
  </div>
</div>

我的表格组件将各种服务作为依赖项,例如用于分页实现的 paginService、进度条、路由器等。它还使用 GridLoadUtil,它提供有关网格将具有的列的信息,并将数据传递给它.

GridLoadUtil

@Injectable()
export class GridLoadUtil {
  columns: Column[] = [];
  columnsChange: Subject<Column[]> = new Subject<Column[]>();

  constructor(protected paginService: PaginationService) {
  }

  setColumns(columnList: Column[]): void {
    this.columns = columnList;
    this.columnsChange.next(this.columns);
  }

  beforeDataLoaded(): void {
    this.paginService.setPaginationDisabled(true);
    this.paginService.setTotalItems([]);
  }

  afterDataLoaded(data): void {
    this.paginService.setTotalItems(data);
    this.paginService.setPaginationDisabled((data.length == 0));
    this.paginService.setActivePage(1);
  }
}

如果同一页面上有多个网格,我将使用指令提供 GridLoadUtil 的新实现,以便所有网格都不会因为其中一个网格的更改而受到影响。

@Directive({
  selector: '[dummy]',
  providers: [{provide: GridLoadUtil, useClass: DummyGridLoadUtil}]
})
export class DummyDirective {
  constructor(private el: ElementRef) {
    console.error("not")
  }
}

如果我的页面有多个网格,这就是它的样子 -

 <xfd-table></xfd-table>

 <xfd-table [dummy]></xfd-table>

我设法让两个表的行为有所不同。但是,对第二个网格的列的更改没有被订阅,因此不会显示在页面上。即使 table.component.ts 获得注入(inject)的 DummyGridLoadUtil 实例,

this.tableLoader.columnsChange.subscribe((values) => {
      this.columns = values;
});

以上部分订阅变量类型(GridLoadUtil)而不是实现(DummyGridLoadUtil)的更改。

有什么办法可以克服这个问题吗?

最佳答案

因此,如果您希望每页有多个表格,则存在严重的设计缺陷。

现在看起来是这样的:

页面有加载数据的服务,并提供网格加载util

表格组件获取注入(inject)的网格加载实用程序,然后页面包装器调用方法来设置列

您正在尝试重新提供带有虚拟指令的 gridloadutil,但是页面包装器当然无法调用 in 上的方法,因为它位于注入(inject)器树中的较低位置。

当您想在一个页面上有多个表时,您需要做的是在不进行重组的情况下为每个表创建包装器。

所以 TableOneWrapperComponent 提供网格加载 util 并具有填充它所需的任何服务,而 TableTwoWrapperComponent 提供它自己的网格加载 util 副本并具有提供它所需的任何服务。

否则,您可以考虑进行较小的重组,以便将列作为输入而不是通过服务提供,因为它看起来像是直接的父/子关系。但是,每个组件都会获取给定服务的一份副本,因此您不能让父组件通过同一服务独立地与两个子组件进行通信。

关于javascript - 订阅派生类上的 Angular2 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46091786/

相关文章:

javascript - typescript 泛型 : types 'T' and 'number' have no overlap error

javascript - 如何在[浏览器选项卡关闭、浏览器关闭、后退、刷新]上调用函数

javascript - 为什么在定义一系列javascript原型(prototype)函数(类方法)时使用逗号?

angular - 如何使用 ng-packagr 添加 Angular 库的 scss 来打包?

angular - 订阅方法不对更改使用react[Angular 2]

typescript - 枚举作为构造函数中的参数会出错

javascript - 想要按升序对数组进行排序,但零应该在最后

javascript - 页面源没有动态 div 元素

angular - Angular 中的通用 http 错误处理

f# - 实现 F# 库以供 TypeScript/Javascript 使用?