在派生类

时间:2017-09-07 08:42:02

标签: 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,progressBar,路由器等。它还使用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获得了DummyGridLoadUtil注入的实例,

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

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

任何想法如何克服这个?

2 个答案:

答案 0 :(得分:1)

因此,如果您每页需要多个表格,则会遇到严重的设计缺陷。

现在好像:

页面包含加载数据的服务并提供网格加载工具

表组件获取网格加载工具注入,然后页面包装器调用方法来设置列

您尝试使用伪指令重新提供gridloadutil,但当然页面包装器无法调用方法,因为它在注入器树中较低。

如果你想在一个页面上拥有多个页面,你需要做的是在没有重组的情况下为每个表创建包装器。

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

否则,您可以考虑进行小规模重组,以便将列作为输入而非通过服务提供,因为它似乎是直接的父/子关系。但是,每个组件都会获得给定服务的一个副本,因此您无法让父级通过相同的服务独立地与两个子级进行通信。

答案 1 :(得分:-1)

我继续改变我的设计。我并没有真正改变很多

<强> Table.component.ts

import {Column} from "../models/Column";
import {Component, Input, OnInit} from "@angular/core";
import {PaginationService} from "../services/PaginationService";
import {GridLoadUtil} from "../util/GridLoadUtil";
import {ProgressBarService} from "../services/ProgressBarService";
import {ActivatedRoute, Router} from "@angular/router";
import {NgbProgressbarConfig} from "@ng-bootstrap/ng-bootstrap";

/**
 * Created by ppandey on 6/12/2017.
 */

@Component({
    selector: 'xfd-table',
    templateUrl: './table.component.html',
    styleUrls: ['./table.component.css'],
    providers: [PaginationService, GridLoadUtil, ProgressBarService]
})
export class TableComponent implements OnInit{
  get columns(): Column[] {
    return this.tableLoader.columns;
  }

  @Input()
  set columns (cols: Column[]) {
    this.tableLoader.setColumns(cols);
  }

  get totalRows(): any[] {
    return this.paginService.getTotalItems();
  }

  @Input()
  set totalRows (row: any[]) {
    this.afterDataLoaded(row);
    this.progressBarService.endProgress();
  }


  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
    });
  }

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

  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);
  }

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

  navigateToEdit(row) {
    this.router.navigate([this.routerLinked + row.userId]);
  }

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

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

我现在正在使用Hierarchial DI来提供父组件的列和行。对于同一页面上的多个表,我将每个表放在它自己的组件中,这是有道理的,因为每个表代表不同的数据和不同的部分。

在每个父组件上,这是我的工作 -

<xfd-table [columns]="sourceTableGridColumns" [totalRows]="sourceTableGridData"></xfd-table>

<xfd-table [columns]="sourceDatabaseGridColumns" [totalRows]="sourceDatabaseGridData"></xfd-table>

这解决了一个问题!而且我的代码仍然是可配置和可重用的。