• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geonetwork / geonetwork-ui / 13518333190

25 Feb 2025 09:50AM UTC coverage: 85.618% (+1.2%) from 84.467%
13518333190

push

github

web-flow
Merge pull request #1120 from geonetwork/paginate-table-compoonent

Datahub: Add pagination for table component

1358 of 1754 branches covered (77.42%)

Branch coverage included in aggregate %.

106 of 121 new or added lines in 10 files covered. (87.6%)

15 existing lines in 1 file now uncovered.

3851 of 4330 relevant lines covered (88.94%)

245.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.0
/libs/ui/dataviz/src/lib/data-table/data-table.component.ts
1
import { ScrollingModule } from '@angular/cdk/scrolling'
1✔
2
import {
1✔
3
  AfterViewInit,
4
  ChangeDetectionStrategy,
5
  ChangeDetectorRef,
6
  Component,
7
  ElementRef,
8
  EventEmitter,
9
  Input,
10
  OnChanges,
11
  OnInit,
12
  Output,
13
  ViewChild,
14
} from '@angular/core'
15
import { MatSort, MatSortModule } from '@angular/material/sort'
1✔
16
import { MatTableModule } from '@angular/material/table'
1✔
17
import { TranslateModule, TranslateService } from '@ngx-translate/core'
1✔
18
import { DataTableDataSource } from './data-table.data.source'
1✔
19
import { BaseReader, FetchError } from '@geonetwork-ui/data-fetcher'
1✔
20
import {
1✔
21
  MatPaginator,
22
  MatPaginatorIntl,
23
  MatPaginatorModule,
24
} from '@angular/material/paginator'
25
import { CustomMatPaginatorIntl } from './custom.mat.paginator.intl'
1✔
26
import { CommonModule } from '@angular/common'
1✔
27
import { BehaviorSubject, filter, firstValueFrom } from 'rxjs'
1✔
28
import {
1✔
29
  LoadingMaskComponent,
30
  PopupAlertComponent,
31
} from '@geonetwork-ui/ui/widgets'
32
import { LetDirective } from '@ngrx/component'
1✔
33

34
const rowIdPrefix = 'table-item-'
1✔
35

36
export type TableItemId = string | number
37
type TableItemType = string | number | Date
38

39
export interface TableItemModel {
40
  id: TableItemId
41
  [key: string]: TableItemType
42
}
43

44
@Component({
45
  standalone: true,
46
  imports: [
47
    MatTableModule,
48
    MatSortModule,
49
    MatPaginatorModule,
50
    ScrollingModule,
51
    TranslateModule,
52
    CommonModule,
53
    LoadingMaskComponent,
54
    PopupAlertComponent,
55
    LetDirective,
56
  ],
57
  providers: [{ provide: MatPaginatorIntl, useClass: CustomMatPaginatorIntl }],
58
  selector: 'gn-ui-data-table',
59
  templateUrl: './data-table.component.html',
60
  styleUrls: ['./data-table.component.css'],
61
  changeDetection: ChangeDetectionStrategy.OnPush,
62
})
63
export class DataTableComponent implements OnInit, AfterViewInit, OnChanges {
1✔
64
  @Input() set dataset(value: BaseReader) {
65
    this.properties$.next(null)
16✔
66
    this.dataset_ = value
16✔
67
    this.dataset_.load()
16✔
68
    this.dataset_.properties.then((properties) =>
16✔
69
      this.properties$.next(properties.map((p) => p.name))
48✔
70
    )
71
    this.dataset_.info.then((info) => (this.count = info.itemsCount))
16✔
72
  }
73
  @Input() activeId: TableItemId
74
  @Output() selected = new EventEmitter<any>()
14✔
75

76
  @ViewChild(MatSort) sort: MatSort
77
  @ViewChild(MatPaginator) paginator: MatPaginator
78

79
  dataset_: BaseReader
80
  properties$ = new BehaviorSubject<string[]>(null)
14✔
81
  dataSource: DataTableDataSource
82
  headerHeight: number
83
  count: number
84
  loading$ = new BehaviorSubject<boolean>(false)
14✔
85
  error = null
14✔
86

87
  constructor(
88
    private eltRef: ElementRef,
14!
89
    private cdr: ChangeDetectorRef,
14!
90
    private translateService: TranslateService
14✔
91
  ) {}
92

93
  ngOnInit() {
94
    this.dataSource = new DataTableDataSource()
14✔
95
  }
96

97
  ngAfterViewInit() {
98
    this.headerHeight =
13✔
99
      this.eltRef.nativeElement.querySelector('thead').offsetHeight
100
    this.setPagination()
13✔
101
    this.cdr.detectChanges()
13✔
102
  }
103

104
  ngOnChanges() {
NEW
105
    this.setPagination()
×
106
  }
107

108
  setSort(sort: MatSort) {
109
    if (!this.dataset_) return
1!
110
    if (!sort.active) {
1!
NEW
111
      this.dataset_.orderBy()
×
112
    } else {
113
      this.dataset_.orderBy([sort.direction || 'asc', sort.active])
1!
114
    }
115
    this.readData()
1✔
116
  }
117

118
  setPagination() {
119
    if (!this.paginator) return
15!
120
    if (!this.dataset_) return
15!
121
    this.dataset_.limit(
15✔
122
      this.paginator.pageIndex * this.paginator.pageSize,
123
      this.paginator.pageSize
124
    )
125
    this.readData()
15✔
126
  }
127

128
  async readData() {
129
    this.loading$.next(true)
17✔
130
    // wait for properties to be read
131
    const properties = await firstValueFrom(
17✔
132
      this.properties$.pipe(filter((p) => !!p))
19✔
133
    )
134
    const propsWithoutGeom = properties.filter(
17✔
135
      (p) => !p.toLowerCase().startsWith('geom')
51✔
136
    )
137
    this.dataset_.select(...propsWithoutGeom)
17✔
138
    try {
17✔
139
      await this.dataSource.showData(this.dataset_.read())
17✔
140
      this.error = null
16✔
141
    } catch (error) {
142
      this.handleError(error as FetchError | Error)
1✔
143
    }
144
    this.loading$.next(false)
17✔
145
  }
146

147
  scrollToItem(itemId: TableItemId): void {
NEW
148
    const row = this.eltRef.nativeElement.querySelector(
×
149
      `#${this.getRowEltId(itemId)}`
150
    )
NEW
151
    this.eltRef.nativeElement.scrollTop = row.offsetTop - this.headerHeight
×
152
  }
153

154
  public getRowEltId(id: TableItemId): string {
NEW
155
    return rowIdPrefix + id
×
156
  }
157

158
  handleError(error: FetchError | Error) {
159
    this.dataSource.clearData()
1✔
160
    if (error instanceof FetchError) {
1!
NEW
161
      this.error = this.translateService.instant(
×
162
        `dataset.error.${error.type}`,
163
        {
164
          info: error.info,
165
        }
166
      )
NEW
167
      console.warn(error.message)
×
168
    } else {
169
      this.error = this.translateService.instant(error.message)
1✔
170
      console.warn(error.stack || error)
1!
171
    }
172
  }
173
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc